don't use function-equal in nadvice
[bpt/emacs.git] / src / xdisp.c
index 3194815..774903b 100644 (file)
@@ -1,6 +1,7 @@
 /* Display generation from window structure and buffer text.
 
-Copyright (C) 1985-1988, 1993-1995, 1997-2013 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2014 Free Software Foundation,
+Inc.
 
 This file is part of GNU Emacs.
 
@@ -97,7 +98,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
       This function attempts to redisplay a window by reusing parts of
       its existing display.  It finds and reuses the part that was not
-      changed, and redraws the rest.
+      changed, and redraws the rest.  (The "id" part in the function's
+      name stands for "insert/delete", not for "identification" or
+      somesuch.)
 
     . try_window
 
@@ -112,6 +115,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    optimizations were successful, redisplay calls redisplay_windows,
    which performs a full redisplay of all windows.
 
+   Note that there's one more important optimization up Emacs's
+   sleeve, but it is related to actually redrawing the potentially
+   changed portions of the window/frame, not to reproducing the
+   desired matrices of those potentially changed portions.  Namely,
+   the function update_frame and its subroutines, which you will find
+   in dispnew.c, compare the desired matrices with the current
+   matrices, and only redraw the portions that changed.  So it could
+   happen that the functions in this file for some reason decide that
+   the entire desired matrix needs to be regenerated from scratch, and
+   still only parts of the Emacs display, or even nothing at all, will
+   be actually delivered to the glass, because update_frame has found
+   that the new and the old screen contents are similar or identical.
+
    Desired matrices.
 
    Desired matrices are always built per Emacs window.  The function
@@ -610,25 +626,31 @@ bool help_echo_showing_p;
 /* Functions to mark elements as needing redisplay.  */
 enum { REDISPLAY_SOME = 2};    /* Arbitrary choice.  */
 
-void redisplay_other_windows (void)
+void
+redisplay_other_windows (void)
 {
   if (!windows_or_buffers_changed)
     windows_or_buffers_changed = REDISPLAY_SOME;
 }
 
-void wset_redisplay (struct window *w)
+void
+wset_redisplay (struct window *w)
 {
-  redisplay_other_windows ();
+  /* Beware: selected_window can be nil during early stages.  */
+  if (!EQ (w->header.self, selected_window))
+    redisplay_other_windows ();
   w->redisplay = true;
 }
 
-void fset_redisplay (struct frame *f)
+void
+fset_redisplay (struct frame *f)
 {
   redisplay_other_windows ();
   f->redisplay = true;
 }
 
-void bset_redisplay (struct buffer *b)
+void
+bset_redisplay (struct buffer *b)
 {
   int count = buffer_window_count (b);
   if (count > 0)
@@ -643,7 +665,8 @@ void bset_redisplay (struct buffer *b)
     }
 }
 
-extern void bset_update_mode_line (struct buffer *b)
+void
+bset_update_mode_line (struct buffer *b)
 {
   if (!update_mode_lines)
     update_mode_lines = REDISPLAY_SOME;
@@ -655,7 +678,7 @@ extern void bset_update_mode_line (struct buffer *b)
 /* Non-zero means print traces of redisplay if compiled with
    GLYPH_DEBUG defined.  */
 
-int trace_redisplay_p;
+bool trace_redisplay_p;
 
 #endif /* GLYPH_DEBUG */
 
@@ -830,7 +853,7 @@ static int single_display_spec_string_p (Lisp_Object, Lisp_Object);
 static int display_prop_string_p (Lisp_Object, Lisp_Object);
 static int row_for_charpos_p (struct glyph_row *, ptrdiff_t);
 static int cursor_row_p (struct glyph_row *);
-static int redisplay_mode_lines (Lisp_Object, int);
+static int redisplay_mode_lines (Lisp_Object, bool);
 static char *decode_mode_spec_coding (Lisp_Object, char *, int);
 
 static Lisp_Object get_it_property (struct it *it, Lisp_Object prop);
@@ -884,7 +907,7 @@ static void sync_frame_with_window_matrix_rows (struct window *);
 static void redisplay_internal (void);
 static int echo_area_display (int);
 static void redisplay_windows (Lisp_Object);
-static void redisplay_window (Lisp_Object, int);
+static void redisplay_window (Lisp_Object, bool);
 static Lisp_Object redisplay_window_error (Lisp_Object);
 static Lisp_Object redisplay_window_0 (Lisp_Object);
 static Lisp_Object redisplay_window_1 (Lisp_Object);
@@ -965,6 +988,7 @@ static int in_ellipses_for_invisible_text_p (struct display_pos *,
 static void x_consider_frame_title (Lisp_Object);
 static void update_tool_bar (struct frame *, int);
 static int redisplay_tool_bar (struct frame *);
+static void x_draw_bottom_divider (struct window *w);
 static void notice_overwritten_cursor (struct window *,
                                        enum glyph_row_area,
                                        int, int, int, int);
@@ -976,7 +1000,7 @@ static void append_stretch_glyph (struct it *, Lisp_Object,
 
 static void produce_special_glyphs (struct it *, enum display_element_type);
 static void show_mouse_face (Mouse_HLInfo *, enum draw_glyphs_face);
-static int coords_in_mouse_face_p (struct window *, int, int);
+static bool coords_in_mouse_face_p (struct window *, int, int);
 
 
 \f
@@ -993,10 +1017,13 @@ static int coords_in_mouse_face_p (struct window *, int, int);
 int
 window_text_bottom_y (struct window *w)
 {
-  int height = WINDOW_TOTAL_HEIGHT (w);
+  int height = WINDOW_PIXEL_HEIGHT (w);
+
+  height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);
 
   if (WINDOW_WANTS_MODELINE_P (w))
     height -= CURRENT_MODE_LINE_HEIGHT (w);
+
   return height;
 }
 
@@ -1007,32 +1034,25 @@ window_text_bottom_y (struct window *w)
 int
 window_box_width (struct window *w, enum glyph_row_area area)
 {
-  int cols = w->total_cols;
-  int pixels = 0;
+  int width = w->pixel_width;
 
   if (!w->pseudo_window_p)
     {
-      cols -= WINDOW_SCROLL_BAR_COLS (w);
+      width -= WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+      width -= WINDOW_RIGHT_DIVIDER_WIDTH (w);
 
       if (area == TEXT_AREA)
-       {
-         cols -= max (0, w->left_margin_cols);
-         cols -= max (0, w->right_margin_cols);
-         pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
-       }
+       width -= (WINDOW_MARGINS_WIDTH (w)
+                  + WINDOW_FRINGES_WIDTH (w));
       else if (area == LEFT_MARGIN_AREA)
-       {
-         cols = max (0, w->left_margin_cols);
-         pixels = 0;
-       }
+       width = WINDOW_LEFT_MARGIN_WIDTH (w);
       else if (area == RIGHT_MARGIN_AREA)
-       {
-         cols = max (0, w->right_margin_cols);
-         pixels = 0;
-       }
+       width = WINDOW_RIGHT_MARGIN_WIDTH (w);
     }
 
-  return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
+  /* With wide margins, fringes, etc. we might end up with a negative
+     width, correct that here.  */
+  return max (0, width);
 }
 
 
@@ -1043,10 +1063,12 @@ int
 window_box_height (struct window *w)
 {
   struct frame *f = XFRAME (w->frame);
-  int height = WINDOW_TOTAL_HEIGHT (w);
+  int height = WINDOW_PIXEL_HEIGHT (w);
 
   eassert (height >= 0);
 
+  height -= WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+
   /* Note: the code below that determines the mode-line/header-line
      height is essentially the same as that contained in the macro
      CURRENT_{MODE,HEADER}_LINE_HEIGHT, except that it checks whether
@@ -1110,7 +1132,8 @@ window_box_left_offset (struct window *w, enum glyph_row_area area)
           && WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
     x += WINDOW_LEFT_FRINGE_WIDTH (w);
 
-  return x;
+  /* Don't return more than the window's pixel width.  */
+  return min (x, w->pixel_width);
 }
 
 
@@ -1121,7 +1144,9 @@ window_box_left_offset (struct window *w, enum glyph_row_area area)
 int
 window_box_right_offset (struct window *w, enum glyph_row_area area)
 {
-  return window_box_left_offset (w, area) + window_box_width (w, area);
+  /* Don't return more than the window's pixel width.  */
+  return min (window_box_left_offset (w, area) + window_box_width (w, area),
+             w->pixel_width);
 }
 
 /* Return the frame-relative coordinate of the left edge of display
@@ -1252,12 +1277,23 @@ Value is the height in pixels of the line at point.  */)
   struct it it;
   struct text_pos pt;
   struct window *w = XWINDOW (selected_window);
+  struct buffer *old_buffer = NULL;
+  Lisp_Object result;
 
+  if (XBUFFER (w->contents) != current_buffer)
+    {
+      old_buffer = current_buffer;
+      set_buffer_internal_1 (XBUFFER (w->contents));
+    }
   SET_TEXT_POS (pt, PT, PT_BYTE);
   start_display (&it, w, pt);
   it.vpos = it.current_y = 0;
   last_height = 0;
-  return make_number (line_bottom_y (&it));
+  result = make_number (line_bottom_y (&it));
+  if (old_buffer)
+    set_buffer_internal_1 (old_buffer);
+
+  return result;
 }
 
 /* Return the default pixel height of text lines in window W.  The
@@ -1424,7 +1460,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
       if (top_y < window_top_y)
        visible_p = bottom_y > window_top_y;
       else if (top_y < it.last_visible_y)
-       visible_p = 1;
+       visible_p = true;
       if (bottom_y >= it.last_visible_y
          && it.bidi_p && it.bidi_it.scan_dir == -1
          && IT_CHARPOS (it) < charpos)
@@ -1662,7 +1698,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
       if (charpos < IT_CHARPOS (it)
          || (it.what == IT_EOB && charpos == IT_CHARPOS (it)))
        {
-         visible_p = 1;
+         visible_p = true;
          RESTORE_IT (&it2, &it2, it2data);
          move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
          *x = it2.current_x;
@@ -1905,6 +1941,7 @@ pixel_to_glyph_coords (struct frame *f, register int pix_x, register int pix_y,
                           FRAME_COLUMN_WIDTH (f) - 1,
                           FRAME_LINE_HEIGHT (f) - 1);
 
+      /* PXW: Should we clip pixels before converting to columns/lines?  */
       if (!noclip)
        {
          if (pix_x < 0)
@@ -2045,7 +2082,10 @@ get_glyph_string_clip_rects (struct glyph_string *s, NativeRectangle *rects, int
     {
       /* Draw full-width.  X coordinates are relative to S->w->left_col.  */
       r.x = WINDOW_LEFT_EDGE_X (s->w);
-      r.width = WINDOW_TOTAL_WIDTH (s->w);
+      if (s->row->mode_line_p)
+       r.width = WINDOW_PIXEL_WIDTH (s->w) - WINDOW_RIGHT_DIVIDER_WIDTH (s->w);
+      else
+       r.width = WINDOW_PIXEL_WIDTH (s->w);
 
       /* Unless displaying a mode or menu bar line, which are always
         fully visible, clip to the visible part of the row.  */
@@ -2313,9 +2353,14 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
-  if (!f->glyphs_initialized_p
-      || (window = window_from_coordinates (f, gx, gy, &part, 0),
-         NILP (window)))
+  if (window_resize_pixelwise)
+    {
+      width = height = 1;
+      goto virtual_glyph;
+    }
+  else if (!f->glyphs_initialized_p
+          || (window = window_from_coordinates (f, gx, gy, &part, 0),
+              NILP (window)))
     {
       width = FRAME_SMALLEST_CHAR_WIDTH (f);
       height = FRAME_SMALLEST_FONT_HEIGHT (f);
@@ -2400,7 +2445,13 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
            }
 
          if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
-           gx += window_box_left_offset (w, area);
+           {
+             gx += window_box_left_offset (w, area);
+             /* Don't expand over the modeline to make sure the vertical
+                drag cursor is shown early enough.  */
+             height = min (height,
+                           max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy));
+           }
        }
       else
        {
@@ -2408,6 +2459,10 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
          gx = (x / width) * width;
          y -= gy;
          gy += (y / height) * height;
+         if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
+           /* See comment above.  */
+           height = min (height,
+                         max (0, WINDOW_BOX_HEIGHT_NO_MODE_LINE (w) - gy));
        }
       break;
 
@@ -2422,7 +2477,22 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
       gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
            ? window_box_right_offset (w, RIGHT_MARGIN_AREA)
            : window_box_right_offset (w, TEXT_AREA));
-      width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+      if (WINDOW_RIGHT_DIVIDER_WIDTH (w) == 0
+         && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
+         && !WINDOW_RIGHTMOST_P (w))
+       if (gx < WINDOW_PIXEL_WIDTH (w) - width)
+         /* Make sure the vertical border can get her own glyph to the
+            right of the one we build here.  */
+         width = WINDOW_RIGHT_FRINGE_WIDTH (w) - width;
+       else
+         width = WINDOW_PIXEL_WIDTH (w) - gx;
+      else
+       width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+
+      goto row_glyph;
+
+    case ON_VERTICAL_BORDER:
+      gx = WINDOW_PIXEL_WIDTH (w) - width;
       goto row_glyph;
 
     case ON_SCROLL_BAR:
@@ -2453,6 +2523,21 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
        }
       break;
 
+    case ON_RIGHT_DIVIDER:
+      gx = WINDOW_PIXEL_WIDTH (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
+      width = WINDOW_RIGHT_DIVIDER_WIDTH (w);
+      gy = 0;
+      /* The bottom divider prevails. */
+      height = WINDOW_PIXEL_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+      goto add_edge;;
+
+    case ON_BOTTOM_DIVIDER:
+      gx = 0;
+      width = WINDOW_PIXEL_WIDTH (w);
+      gy = WINDOW_PIXEL_HEIGHT (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+      height = WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+      goto add_edge;
+
     default:
       ;
     virtual_glyph:
@@ -2473,6 +2558,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
       goto store_rect;
     }
 
+ add_edge:
   gx += WINDOW_LEFT_EDGE_X (w);
   gy += WINDOW_TOP_EDGE_Y (w);
 
@@ -2520,8 +2606,8 @@ safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args)
    following.  Return the result, or nil if something went
    wrong.  Prevent redisplay during the evaluation.  */
 
-Lisp_Object
-safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+static Lisp_Object
+safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap)
 {
   Lisp_Object val;
 
@@ -2529,32 +2615,42 @@ safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
     val = Qnil;
   else
     {
-      va_list ap;
       ptrdiff_t i;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       struct gcpro gcpro1;
       Lisp_Object *args = alloca (nargs * word_size);
 
       args[0] = func;
-      va_start (ap, func);
       for (i = 1; i < nargs; i++)
        args[i] = va_arg (ap, Lisp_Object);
-      va_end (ap);
 
       GCPRO1 (args[0]);
       gcpro1.nvars = nargs;
       specbind (Qinhibit_redisplay, Qt);
+      if (inhibit_quit)
+       specbind (Qinhibit_quit, Qt);
       /* Use Qt to ensure debugger does not run,
         so there is no possibility of wanting to redisplay.  */
       val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
                                       safe_eval_handler);
       UNGCPRO;
-      val = unbind_to (count, val);
+      dynwind_end ();
     }
 
   return val;
 }
 
+Lisp_Object
+safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+{
+  Lisp_Object retval;
+  va_list ap;
+
+  va_start (ap, func);
+  retval = safe__call (false, nargs, func, ap);
+  va_end (ap);
+  return retval;
+}
 
 /* Call function FN with one argument ARG.
    Return the result, or nil if something went wrong.  */
@@ -2565,12 +2661,30 @@ safe_call1 (Lisp_Object fn, Lisp_Object arg)
   return safe_call (2, fn, arg);
 }
 
+static Lisp_Object
+safe__call1 (bool inhibit_quit, Lisp_Object fn, ...)
+{
+  Lisp_Object retval;
+  va_list ap;
+
+  va_start (ap, fn);
+  retval = safe__call (inhibit_quit, 2, fn, ap);
+  va_end (ap);
+  return retval;
+}
+
 static Lisp_Object Qeval;
 
 Lisp_Object
 safe_eval (Lisp_Object sexpr)
 {
-  return safe_call1 (Qeval, sexpr);
+  return safe__call1 (false, Qeval, sexpr);
+}
+
+static Lisp_Object
+safe__eval (bool inhibit_quit, Lisp_Object sexpr)
+{
+  return safe__call1 (inhibit_quit, Qeval, sexpr);
 }
 
 /* Call function FN with two arguments ARG1 and ARG2.
@@ -2790,8 +2904,9 @@ init_iterator (struct it *it, struct window *w,
     it->redisplay_end_trigger_charpos
       = marker_position (w->redisplay_end_trigger);
   else if (INTEGERP (w->redisplay_end_trigger))
-    it->redisplay_end_trigger_charpos =
-      clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger), PTRDIFF_MAX);
+    it->redisplay_end_trigger_charpos
+      = clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger),
+                       PTRDIFF_MAX);
 
   it->tab_width = SANE_TAB_WIDTH (current_buffer);
 
@@ -2802,6 +2917,7 @@ init_iterator (struct it *it, struct window *w,
          && ((!NILP (Vtruncate_partial_width_windows)
               && !INTEGERP (Vtruncate_partial_width_windows))
              || (INTEGERP (Vtruncate_partial_width_windows)
+                 /* PXW: Shall we do something about this?  */
                  && (WINDOW_TOTAL_COLS (it->w)
                      < XINT (Vtruncate_partial_width_windows))))))
     it->line_wrap = TRUNCATE;
@@ -2861,12 +2977,12 @@ init_iterator (struct it *it, struct window *w,
     {
       /* Mode lines, menu bar in terminal frames.  */
       it->first_visible_x = 0;
-      it->last_visible_x = WINDOW_TOTAL_WIDTH (w);
+      it->last_visible_x = WINDOW_PIXEL_WIDTH (w);
     }
   else
     {
-      it->first_visible_x =
-       window_hscroll_limited (it->w, it->f) * FRAME_COLUMN_WIDTH (it->f);
+      it->first_visible_x
+       window_hscroll_limited (it->w, it->f) * FRAME_COLUMN_WIDTH (it->f);
       it->last_visible_x = (it->first_visible_x
                            + window_box_width (w, TEXT_AREA));
 
@@ -2907,8 +3023,8 @@ init_iterator (struct it *it, struct window *w,
       /* If we have a boxed mode line, make the first character appear
         with a left box line.  */
       face = FACE_FROM_ID (it->f, remapped_base_face_id);
-      if (face->box != FACE_NO_BOX)
-       it->start_of_box_run_p = 1;
+      if (face && face->box != FACE_NO_BOX)
+       it->start_of_box_run_p = true;
     }
 
   /* If a buffer position was specified, set the iterator there,
@@ -3336,7 +3452,7 @@ handle_stop (struct it *it)
                pop_it (it);
              else
                {
-                 it->ignore_overlay_strings_at_pos_p = 1;
+                 it->ignore_overlay_strings_at_pos_p = true;
                  it->string_from_display_prop_p = 0;
                  it->from_disp_prop_p = 0;
                  handle_overlay_change_p = 0;
@@ -3695,7 +3811,7 @@ handle_fontified_prop (struct it *it)
             no amount of fontifying will be able to change it.  */
          NILP (prop) && IT_CHARPOS (*it) < Z))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       Lisp_Object val;
       struct buffer *obuf = current_buffer;
       ptrdiff_t begv = BEGV, zv = ZV;
@@ -3743,7 +3859,7 @@ handle_fontified_prop (struct it *it)
          UNGCPRO;
        }
 
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       /* Fontification functions routinely call `save-restriction'.
         Normally, this tags clip_changed, which can confuse redisplay
@@ -3892,6 +4008,15 @@ handle_face_prop (struct it *it)
             For strings from wrap-prefix and line-prefix properties,
             use the default face, possibly remapped via
             Vface_remapping_alist.  */
+         /* Note that the fact that we use the face at _buffer_
+            position means that a 'display' property on an overlay
+            string will not inherit the face of that overlay string,
+            but will instead revert to the face of buffer text
+            covered by the overlay.  This is visible, e.g., when the
+            overlay specifies a box face, but neither the buffer nor
+            the display string do.  This sounds like a design bug,
+            but Emacs always did that since v21.1, so changing that
+            might be a big deal.  */
          base_face_id = it->string_from_prefix_prop_p
            ? (!NILP (Vface_remapping_alist)
               ? lookup_basic_face (it->f, DEFAULT_FACE_ID)
@@ -4201,13 +4326,13 @@ handle_invisible_prop (struct it *it)
                  prop = Fget_text_property (end_charpos, Qinvisible, it->string);
                  invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
                  if (invis_p == 2)
-                   display_ellipsis_p = 1;
+                   display_ellipsis_p = true;
                }
            }
          while (invis_p && endpos < len);
 
          if (display_ellipsis_p)
-           it->ellipsis_p = 1;
+           it->ellipsis_p = true;
 
          if (endpos < len)
            {
@@ -4319,9 +4444,9 @@ handle_invisible_prop (struct it *it)
                tem = next_stop;
 
               /* If there are adjacent invisible texts, don't lose the
-                 second one's ellipsis. */
+                 second one's ellipsis.  */
               if (invis_p == 2)
-                display_ellipsis_p = 1;
+                display_ellipsis_p = true;
            }
          while (invis_p);
 
@@ -4329,10 +4454,10 @@ handle_invisible_prop (struct it *it)
          if (it->bidi_p)
            {
              ptrdiff_t bpos = CHAR_TO_BYTE (newpos);
-             int on_newline =
-               bpos == ZV_BYTE || FETCH_BYTE (bpos) == '\n';
-             int after_newline =
-               newpos <= BEGV || FETCH_BYTE (bpos - 1) == '\n';
+             int on_newline
+               bpos == ZV_BYTE || FETCH_BYTE (bpos) == '\n';
+             int after_newline
+               newpos <= BEGV || FETCH_BYTE (bpos - 1) == '\n';
 
              /* If the invisible text ends on a newline or on a
                 character after a newline, we can avoid the costly,
@@ -4439,7 +4564,7 @@ handle_invisible_prop (struct it *it)
                  it->position.charpos = newpos - 1;
                  it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
                }
-             it->ellipsis_p = 1;
+             it->ellipsis_p = true;
              /* Let the ellipsis display before
                 considering any properties of the following char.
                 Fixes jasonr@gnu.org 01 Oct 07 bug.  */
@@ -4484,7 +4609,7 @@ setup_for_ellipsis (struct it *it, int len)
     it->saved_face_id = it->face_id = DEFAULT_FACE_ID;
 
   it->method = GET_FROM_DISPLAY_VECTOR;
-  it->ellipsis_p = 1;
+  it->ellipsis_p = true;
 }
 
 
@@ -4698,7 +4823,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 
   if (!NILP (form) && !EQ (form, Qt))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       struct gcpro gcpro1;
 
       /* Bind `object' to the object having the `display' property, a
@@ -4714,7 +4839,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
       GCPRO1 (form);
       form = safe_eval (form);
       UNGCPRO;
-      unbind_to (count, Qnil);
+      dynwind_end ();
     }
 
   if (NILP (form))
@@ -4772,11 +4897,11 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                {
                  /* Evaluate IT->font_height with `height' bound to the
                     current specified height to get the new height.  */
-                 ptrdiff_t count = SPECPDL_INDEX ();
+                 dynwind_begin ();
 
                  specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
                  value = safe_eval (it->font_height);
-                 unbind_to (count, Qnil);
+                 dynwind_end ();
 
                  if (NUMBERP (value))
                    new_height = XFLOATINT (value);
@@ -4953,7 +5078,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->method = GET_FROM_IMAGE;
          it->from_overlay = Qnil;
          it->face_id = face_id;
-         it->from_disp_prop_p = 1;
+         it->from_disp_prop_p = true;
 
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
@@ -5035,7 +5160,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
         when we are finished with the glyph property value.  */
       push_it (it, position);
       it->from_overlay = overlay;
-      it->from_disp_prop_p = 1;
+      it->from_disp_prop_p = true;
 
       if (NILP (location))
        it->area = TEXT_AREA;
@@ -5055,7 +5180,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->stop_charpos = 0;
          it->prev_stop = 0;
          it->base_level_stop = 0;
-         it->string_from_display_prop_p = 1;
+         it->string_from_display_prop_p = true;
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
             set_iterator_to_next will clean this up.  */
@@ -5421,7 +5546,7 @@ next_overlay_string (struct it *it)
         processed the overlay strings there already, so that
         next_element_from_buffer doesn't try it again.  */
       if (NILP (it->string) && IT_CHARPOS (*it) >= it->end_charpos)
-       it->overlay_strings_at_end_processed_p = 1;
+       it->overlay_strings_at_end_processed_p = true;
     }
   else
     {
@@ -5925,7 +6050,16 @@ pop_it (struct it *it)
       it->object = it->w->contents;
       break;
     case GET_FROM_STRING:
-      it->object = it->string;
+      {
+       struct face *face = FACE_FROM_ID (it->f, it->face_id);
+
+       /* Restore the face_box_p flag, since it could have been
+          overwritten by the face of the object that we just finished
+          displaying.  */
+       if (face)
+         it->face_box_p = face->box != FACE_NO_BOX;
+       it->object = it->string;
+      }
       break;
     case GET_FROM_DISPLAY_VECTOR:
       if (it->s)
@@ -6104,7 +6238,7 @@ forward_to_next_line_start (struct it *it, int *skipped_p,
              if (bidi_it_prev)
                *bidi_it_prev = bprev;
            }
-         *skipped_p = newline_found_p = 1;
+         *skipped_p = newline_found_p = true;
        }
       else
        {
@@ -6394,6 +6528,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
       it->bidi_it.string.s = NULL;
       it->bidi_it.string.lstring = Qnil;
       it->bidi_it.string.bufpos = 0;
+      it->bidi_it.string.from_disp_str = 0;
       it->bidi_it.string.unibyte = 0;
       it->bidi_it.w = it->w;
     }
@@ -6794,9 +6929,9 @@ get_next_display_element (struct it *it)
          if (! ASCII_CHAR_P (c) && ! NILP (Vnobreak_char_display))
            {
              if (c == 0xA0)
-               nonascii_space_p = 1;
+               nonascii_space_p = true;
              else if (c == 0xAD || c == 0x2010 || c == 0x2011)
-               nonascii_hyphen_p = 1;
+               nonascii_hyphen_p = true;
            }
 
          /* Translate control characters into `\003' or `^C' form.
@@ -7011,21 +7146,44 @@ get_next_display_element (struct it *it)
                 If this is the last string character displayed, check
                 the next buffer location.  */
              else if ((IT_STRING_CHARPOS (*it) >= SCHARS (it->string) - 1)
-                      && (it->current.overlay_string_index
-                          == it->n_overlay_strings - 1))
+                      /* n_overlay_strings is unreliable unless
+                         overlay_string_index is non-negative.  */
+                      && ((it->current.overlay_string_index >= 0
+                           && (it->current.overlay_string_index
+                               == it->n_overlay_strings - 1))
+                          /* A string from display property.  */
+                          || it->from_disp_prop_p))
                {
                  ptrdiff_t ignore;
                  int next_face_id;
                  struct text_pos pos = it->current.pos;
-                 INC_TEXT_POS (pos, it->multibyte_p);
 
-                 next_face_id = face_at_buffer_position
-                   (it->w, CHARPOS (pos), &ignore,
-                    (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT), 0,
-                    -1);
-                 it->end_of_box_run_p
-                   = (FACE_FROM_ID (it->f, next_face_id)->box
-                      == FACE_NO_BOX);
+                 /* For a string from a display property, the next
+                    buffer position is stored in the 'position'
+                    member of the iteration stack slot below the
+                    current one, see handle_single_display_spec.  By
+                    contrast, it->current.pos was is not yet updated
+                    to point to that buffer position; that will
+                    happen in pop_it, after we finish displaying the
+                    current string.  Note that we already checked
+                    above that it->sp is positive, so subtracting one
+                    from it is safe.  */
+                 if (it->from_disp_prop_p)
+                   pos = (it->stack + it->sp - 1)->position;
+                 else
+                   INC_TEXT_POS (pos, it->multibyte_p);
+
+                 if (CHARPOS (pos) >= ZV)
+                   it->end_of_box_run_p = true;
+                 else
+                   {
+                     next_face_id = face_at_buffer_position
+                       (it->w, CHARPOS (pos), &ignore,
+                        CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, 0, -1);
+                     it->end_of_box_run_p
+                       = (FACE_FROM_ID (it->f, next_face_id)->box
+                          == FACE_NO_BOX);
+                   }
                }
            }
        }
@@ -7255,12 +7413,12 @@ set_iterator_to_next (struct it *it, int reseat_p)
              if (it->method == GET_FROM_STRING
                  && it->current.overlay_string_index >= 0
                  && it->n_overlay_strings > 0)
-               it->ignore_overlay_strings_at_pos_p = 1;
+               it->ignore_overlay_strings_at_pos_p = true;
              it->len = it->dpvec_char_len;
              set_iterator_to_next (it, reseat_p);
            }
 
-         /* Maybe recheck faces after display vector */
+         /* Maybe recheck faces after display vector */
          if (recheck_faces)
            it->stop_charpos = IT_CHARPOS (*it);
        }
@@ -7285,7 +7443,7 @@ set_iterator_to_next (struct it *it, int reseat_p)
       else
        {
          /* Not an overlay string.  There could be padding, so test
-            against it->end_charpos . */
+            against it->end_charpos */
          if (IT_STRING_CHARPOS (*it) >= it->end_charpos)
            goto consider_string_end;
        }
@@ -7797,7 +7955,7 @@ next_element_from_string (struct it *it)
 static int
 next_element_from_c_string (struct it *it)
 {
-  int success_p = 1;
+  bool success_p = true;
 
   eassert (it->s);
   eassert (!it->bidi_p || it->s == it->bidi_it.string.s);
@@ -7856,7 +8014,7 @@ next_element_from_ellipsis (struct it *it)
       it->method = GET_FROM_BUFFER;
       it->object = it->w->contents;
       reseat_at_next_visible_line_start (it, 1);
-      it->face_before_selective_p = 1;
+      it->face_before_selective_p = true;
     }
 
   return GET_NEXT_DISPLAY_ELEMENT (it);
@@ -7925,7 +8083,7 @@ compute_stop_pos_backwards (struct it *it)
     it->prev_stop = it->stop_charpos;
   else
     it->prev_stop = BEGV;
-  it->bidi_p = 1;
+  it->bidi_p = true;
   it->current = save_current;
   it->position = save_position;
   it->stop_charpos = save_stop_pos;
@@ -7971,7 +8129,7 @@ handle_stop_backwards (struct it *it, ptrdiff_t charpos)
     }
   while (charpos <= where_we_are);
 
-  it->bidi_p = 1;
+  it->bidi_p = true;
   it->current = save_current;
   it->position = save_position;
   next_stop = it->stop_charpos;
@@ -7988,7 +8146,7 @@ handle_stop_backwards (struct it *it, ptrdiff_t charpos)
 static int
 next_element_from_buffer (struct it *it)
 {
-  int success_p = 1;
+  bool success_p = true;
 
   eassert (IT_CHARPOS (*it) >= BEGV);
   eassert (NILP (it->string) && !it->s);
@@ -8018,7 +8176,7 @@ next_element_from_buffer (struct it *it)
            overlay_strings_follow_p = 0;
          else
            {
-             it->overlay_strings_at_end_processed_p = 1;
+             it->overlay_strings_at_end_processed_p = true;
              overlay_strings_follow_p = get_overlay_strings (it, 0);
            }
 
@@ -8111,7 +8269,7 @@ next_element_from_buffer (struct it *it)
 
       /* Get the next character, maybe multibyte.  */
       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
-      if (it->multibyte_p && !ASCII_BYTE_P (*p))
+      if (it->multibyte_p && !ASCII_CHAR_P (*p))
        it->c = STRING_CHAR_AND_LENGTH (p, it->len);
       else
        it->c = *p, it->len = 1;
@@ -8291,7 +8449,7 @@ move_it_in_display_line_to (struct it *it,
   void *ppos_data = NULL;
   int may_wrap = 0;
   enum it_method prev_method = it->method;
-  ptrdiff_t prev_pos = IT_CHARPOS (*it);
+  ptrdiff_t closest_pos IF_LINT (= 0), prev_pos = IT_CHARPOS (*it);
   int saw_smaller_pos = prev_pos < to_charpos;
 
   /* Don't produce glyphs in produce_glyphs.  */
@@ -8308,16 +8466,21 @@ move_it_in_display_line_to (struct it *it,
   atx_it.sp = -1;
 
   /* Use ppos_it under bidi reordering to save a copy of IT for the
-     position > CHARPOS that is the closest to CHARPOS.  We restore
-     that position in IT when we have scanned the entire display line
-     without finding a match for CHARPOS and all the character
-     positions are greater than CHARPOS.  */
+     initial position.  We restore that position in IT when we have
+     scanned the entire display line without finding a match for
+     TO_CHARPOS and all the character positions are greater than
+     TO_CHARPOS.  We then restart the scan from the initial position,
+     and stop at CLOSEST_POS, which is a position > TO_CHARPOS that is
+     the closest to TO_CHARPOS.  */
   if (it->bidi_p)
     {
-      SAVE_IT (ppos_it, *it, ppos_data);
-      SET_TEXT_POS (ppos_it.current.pos, ZV, ZV_BYTE);
       if ((op & MOVE_TO_POS) && IT_CHARPOS (*it) >= to_charpos)
-       SAVE_IT (ppos_it, *it, ppos_data);
+       {
+         SAVE_IT (ppos_it, *it, ppos_data);
+         closest_pos = IT_CHARPOS (*it);
+       }
+      else
+       closest_pos = ZV;
     }
 
 #define BUFFER_POS_REACHED_P()                                 \
@@ -8408,7 +8571,7 @@ move_it_in_display_line_to (struct it *it,
        }
       else
        {
-         if (it->line_wrap == WORD_WRAP)
+         if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA)
            {
              if (IT_DISPLAYING_WHITESPACE (it))
                may_wrap = 1;
@@ -8461,8 +8624,8 @@ move_it_in_display_line_to (struct it *it,
          if (it->bidi_p
              && (op & MOVE_TO_POS)
              && IT_CHARPOS (*it) > to_charpos
-             && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
-           SAVE_IT (ppos_it, *it, ppos_data);
+             && IT_CHARPOS (*it) < closest_pos)
+           closest_pos = IT_CHARPOS (*it);
          continue;
        }
 
@@ -8542,7 +8705,12 @@ move_it_in_display_line_to (struct it *it,
                         doesn't fit on the line, e.g. a wide image.  */
                      it->hpos == 0
                      || (new_x == it->last_visible_x
-                         && FRAME_WINDOW_P (it->f)))
+                         && FRAME_WINDOW_P (it->f)
+                         /* When word-wrap is ON and we have a valid
+                            wrap point, we don't allow the last glyph
+                            to "just barely fit" on the line.  */
+                         && (it->line_wrap != WORD_WRAP
+                             || wrap_it.sp < 0)))
                    {
                      ++it->hpos;
                      it->current_x = new_x;
@@ -8684,9 +8852,14 @@ move_it_in_display_line_to (struct it *it,
            {
              if (!saw_smaller_pos && IT_CHARPOS (*it) > to_charpos)
                {
-                 if (IT_CHARPOS (ppos_it) < ZV)
+                 if (closest_pos < ZV)
                    {
                      RESTORE_IT (it, &ppos_it, ppos_data);
+                     /* Don't recurse if closest_pos is equal to
+                        to_charpos, since we have just tried that.  */
+                     if (closest_pos != to_charpos)
+                       move_it_in_display_line_to (it, closest_pos, -1,
+                                                   MOVE_TO_POS);
                      result = MOVE_POS_MATCH_OR_ZV;
                    }
                  else
@@ -8716,8 +8889,8 @@ move_it_in_display_line_to (struct it *it,
       if (it->bidi_p
          && (op & MOVE_TO_POS)
          && IT_CHARPOS (*it) >= to_charpos
-         && IT_CHARPOS (*it) < IT_CHARPOS (ppos_it))
-       SAVE_IT (ppos_it, *it, ppos_data);
+         && IT_CHARPOS (*it) < closest_pos)
+       closest_pos = IT_CHARPOS (*it);
 
       /* Stop if lines are truncated and IT's current x-position is
         past the right edge of the window now.  */
@@ -8743,8 +8916,14 @@ move_it_in_display_line_to (struct it *it,
                      && IT_CHARPOS (*it) > to_charpos))
                {
                  if (it->bidi_p
-                     && !at_eob_p && IT_CHARPOS (ppos_it) < ZV)
-                   RESTORE_IT (it, &ppos_it, ppos_data);
+                     && !BUFFER_POS_REACHED_P ()
+                     && !at_eob_p && closest_pos < ZV)
+                   {
+                     RESTORE_IT (it, &ppos_it, ppos_data);
+                     if (closest_pos != to_charpos)
+                       move_it_in_display_line_to (it, closest_pos, -1,
+                                                   MOVE_TO_POS);
+                   }
                  result = MOVE_POS_MATCH_OR_ZV;
                  break;
                }
@@ -8758,8 +8937,13 @@ move_it_in_display_line_to (struct it *it,
                   && !saw_smaller_pos
                   && IT_CHARPOS (*it) > to_charpos)
            {
-             if (IT_CHARPOS (ppos_it) < ZV)
-               RESTORE_IT (it, &ppos_it, ppos_data);
+             if (closest_pos < ZV)
+               {
+                 RESTORE_IT (it, &ppos_it, ppos_data);
+                 if (closest_pos != to_charpos)
+                   move_it_in_display_line_to (it, closest_pos, -1,
+                                               MOVE_TO_POS);
+               }
              result = MOVE_POS_MATCH_OR_ZV;
              break;
            }
@@ -8838,13 +9022,17 @@ move_it_in_display_line (struct it *it,
 
    If TO_CHARPOS is in invisible text, e.g. a truncated part of a
    screen line, this function will set IT to the next position that is
-   displayed to the right of TO_CHARPOS on the screen.  */
+   displayed to the right of TO_CHARPOS on the screen.
 
-void
+   Return the maximum pixel length of any line scanned but never more
+   than it.last_visible_x.  */
+
+int
 move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos, int op)
 {
   enum move_it_result skip, skip2 = MOVE_X_REACHED;
   int line_height, line_start_x = 0, reached = 0;
+  int max_current_x = 0;
   void *backup_data = NULL;
 
   for (;;)
@@ -8975,6 +9163,9 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
              if (to_y >= it->current_y
                  && to_y < it->current_y + line_height)
                {
+                 if (to_y > it->current_y)
+                   max_current_x = max (it->current_x, max_current_x);
+
                  /* When word-wrap is on, TO_X may lie past the end
                     of a wrapped line.  Then it->current is the
                     character on the next line, so backtrack to the
@@ -8987,12 +9178,16 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
                      skip = move_it_in_display_line_to
                        (it, -1, prev_x, MOVE_TO_X);
                    }
+
                  reached = 6;
                }
            }
 
          if (reached)
-           break;
+           {
+             max_current_x = max (it->current_x, max_current_x);
+             break;
+           }
        }
       else if (BUFFERP (it->object)
               && (it->method == GET_FROM_BUFFER
@@ -9012,15 +9207,18 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
       switch (skip)
        {
        case MOVE_POS_MATCH_OR_ZV:
+         max_current_x = max (it->current_x, max_current_x);
          reached = 8;
          goto out;
 
        case MOVE_NEWLINE_OR_CR:
+         max_current_x = max (it->current_x, max_current_x);
          set_iterator_to_next (it, 1);
          it->continuation_lines_width = 0;
          break;
 
        case MOVE_LINE_TRUNCATED:
+         max_current_x = it->last_visible_x;
          it->continuation_lines_width = 0;
          reseat_at_next_visible_line_start (it, 0);
          if ((op & MOVE_TO_POS) != 0
@@ -9032,6 +9230,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
          break;
 
        case MOVE_LINE_CONTINUED:
+         max_current_x = it->last_visible_x;
          /* For continued lines ending in a tab, some of the glyphs
             associated with the tab are displayed on the current
             line.  Since it->current_x does not include these glyphs,
@@ -9099,6 +9298,8 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
     bidi_unshelve_cache (backup_data, 1);
 
   TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
+
+  return max_current_x;
 }
 
 
@@ -9370,6 +9571,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
       ptrdiff_t start_charpos, i;
       int nchars_per_row
        = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
+      bool hit_pos_limit = false;
       ptrdiff_t pos_limit;
 
       /* Start at the beginning of the screen line containing IT's
@@ -9386,8 +9588,11 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
        pos_limit = BEGV;
       else
        pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
+
       for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i)
        back_to_previous_visible_line_start (it);
+      if (i > 0 && IT_CHARPOS (*it) <= pos_limit)
+       hit_pos_limit = true;
       reseat (it, it->current.pos, 1);
 
       /* Move further back if we end up in a string or an image.  */
@@ -9431,14 +9636,33 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
          else
            bidi_unshelve_cache (it2data, 1);
        }
+      else if (hit_pos_limit && pos_limit > BEGV
+              && dvpos < 0 && it2.vpos < -dvpos)
+       {
+         /* If we hit the limit, but still didn't make it far enough
+            back, that means there's a display string with a newline
+            covering a large chunk of text, and that caused
+            back_to_previous_visible_line_start try to go too far.
+            Punish those who commit such atrocities by going back
+            until we've reached DVPOS, after lifting the limit, which
+            could make it slow for very long lines.  "If it hurts,
+            don't do that!"  */
+         dvpos += it2.vpos;
+         RESTORE_IT (it, it, it2data);
+         for (i = -dvpos; i > 0; --i)
+           {
+             back_to_previous_visible_line_start (it);
+             it->vpos--;
+           }
+       }
       else
        RESTORE_IT (it, it, it2data);
     }
 }
 
-/* Return 1 if IT points into the middle of a display vector.  */
+/* Return true if IT points into the middle of a display vector.  */
 
-int
+bool
 in_display_vector_p (struct it *it)
 {
   return (it->method == GET_FROM_DISPLAY_VECTOR
@@ -9446,6 +9670,141 @@ in_display_vector_p (struct it *it)
          && it->dpvec + it->current.dpvec_index != it->dpend);
 }
 
+DEFUN ("window-text-pixel-size", Fwindow_text_pixel_size, Swindow_text_pixel_size, 0, 6, 0,
+       doc: /* Return the size of the text of WINDOW's buffer in pixels.
+WINDOW must be a live window and defaults to the selected one.  The
+return value is a cons of the maximum pixel-width of any text line and
+the maximum pixel-height of all text lines.
+
+The optional argument FROM, if non-nil, specifies the first text
+position and defaults to the minimum accessible position of the buffer.
+If FROM is t, use the minimum accessible position that is not a newline
+character.  TO, if non-nil, specifies the last text position and
+defaults to the maximum accessible position of the buffer.  If TO is t,
+use the maximum accessible position that is not a newline character.
+
+The optional argument X-LIMIT, if non-nil, specifies the maximum text
+width that can be returned.  X-LIMIT nil or omitted, means to use the
+pixel-width of WINDOW's body; use this if you do not intend to change
+the width of WINDOW.  Use the maximum width WINDOW may assume if you
+intend to change WINDOW's width.  In any case, text whose x-coordinate
+is beyond X-LIMIT is ignored.  Since calculating the width of long lines
+can take some time, it's always a good idea to make this argument as
+small as possible; in particular, if the buffer contains long lines that
+shall be truncated anyway.
+
+The optional argument Y-LIMIT, if non-nil, specifies the maximum text
+height that can be returned.  Text lines whose y-coordinate is beyond
+Y-LIMIT are ignored.  Since calculating the text height of a large
+buffer can take some time, it makes sense to specify this argument if
+the size of the buffer is unknown.
+
+Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
+include the height of the mode- or header-line of WINDOW in the return
+value.  If it is either the symbol `mode-line' or `header-line', include
+only the height of that line, if present, in the return value.  If t,
+include the height of both, if present, in the return value.  */)
+  (Lisp_Object window, Lisp_Object from, Lisp_Object to, Lisp_Object x_limit, Lisp_Object y_limit,
+   Lisp_Object mode_and_header_line)
+{
+  struct window *w = decode_live_window (window);
+  Lisp_Object buf;
+  struct buffer *b;
+  struct it it;
+  struct buffer *old_buffer = NULL;
+  ptrdiff_t start, end, pos;
+  struct text_pos startp;
+  void *itdata = NULL;
+  int c, max_y = -1, x = 0, y = 0;
+
+  buf = w->contents;
+  CHECK_BUFFER (buf);
+  b = XBUFFER (buf);
+
+  if (b != current_buffer)
+    {
+      old_buffer = current_buffer;
+      set_buffer_internal (b);
+    }
+
+  if (NILP (from))
+    start = BEGV;
+  else if (EQ (from, Qt))
+    {
+      start = pos = BEGV;
+      while ((pos++ < ZV) && (c = FETCH_CHAR (pos))
+            && (c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+       start = pos;
+      while ((pos-- > BEGV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t'))
+       start = pos;
+    }
+  else
+    {
+      CHECK_NUMBER_COERCE_MARKER (from);
+      start = min (max (XINT (from), BEGV), ZV);
+    }
+
+  if (NILP (to))
+    end = ZV;
+  else if (EQ (to, Qt))
+    {
+      end = pos = ZV;
+      while ((pos-- > BEGV) && (c = FETCH_CHAR (pos))
+            && (c == ' ' || c == '\t' || c == '\n' || c == '\r'))
+       end = pos;
+      while ((pos++ < ZV) && (c = FETCH_CHAR (pos)) && (c == ' ' || c == '\t'))
+       end = pos;
+    }
+  else
+    {
+      CHECK_NUMBER_COERCE_MARKER (to);
+      end = max (start, min (XINT (to), ZV));
+    }
+
+  if (!NILP (y_limit))
+    {
+      CHECK_NUMBER (y_limit);
+      max_y = min (XINT (y_limit), INT_MAX);
+    }
+
+  itdata = bidi_shelve_cache ();
+  SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
+  start_display (&it, w, startp);
+
+  if (NILP (x_limit))
+    x = move_it_to (&it, end, -1, max_y, -1, MOVE_TO_POS | MOVE_TO_Y);
+  else
+    {
+      CHECK_NUMBER (x_limit);
+      it.last_visible_x = min (XINT (x_limit), INFINITY);
+      /* Actually, we never want move_it_to stop at to_x.  But to make
+        sure that move_it_in_display_line_to always moves far enough,
+        we set it to INT_MAX and specify MOVE_TO_X.  */
+      x = move_it_to (&it, end, INT_MAX, max_y, -1,
+                     MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+    }
+
+  y = it.current_y + it.max_ascent + it.max_descent;
+
+  if (!EQ (mode_and_header_line, Qheader_line)
+      && !EQ (mode_and_header_line, Qt))
+    /* Do not count the header-line which was counted automatically by
+       start_display.  */
+    y = y - WINDOW_HEADER_LINE_HEIGHT (w);
+
+  if (EQ (mode_and_header_line, Qmode_line)
+      || EQ (mode_and_header_line, Qt))
+    /* Do count the mode-line which is not included automatically by
+       start_display.  */
+    y = y + WINDOW_MODE_LINE_HEIGHT (w);
+
+  bidi_unshelve_cache (itdata, 0);
+
+  if (old_buffer)
+    set_buffer_internal (old_buffer);
+
+  return Fcons (make_number (x), make_number (y));
+}
 \f
 /***********************************************************************
                               Messages
@@ -9573,9 +9932,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
          for (i = 0; i < nbytes; i += char_bytes)
            {
              c = string_char_and_length (msg + i, &char_bytes);
-             work[0] = (ASCII_CHAR_P (c)
-                        ? c
-                        : multibyte_char_to_unibyte (c));
+             work[0] = CHAR_TO_BYTE8 (c);
              insert_1_both (work, 1, 1, 1, 0, 0);
            }
        }
@@ -9681,7 +10038,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
         incrementing windows_or_buffers_changed even if *Messages* is
         shown in some window.  So we must manually set
         windows_or_buffers_changed here to make up for that.  */
-       windows_or_buffers_changed = old_windows_or_buffers_changed;
+      windows_or_buffers_changed = old_windows_or_buffers_changed;
       bset_redisplay (current_buffer);
 
       set_buffer_internal (oldbuf);
@@ -9741,7 +10098,7 @@ message3 (Lisp_Object m)
   struct gcpro gcpro1;
 
   GCPRO1 (m);
-  clear_message (1,1);
+  clear_message (true, true);
   cancel_echoing ();
 
   /* First flush out any partial line written with print.  */
@@ -9811,7 +10168,7 @@ message3_nolog (Lisp_Object m)
          echo_message_buffer = Qnil;
        }
       else
-       clear_message (1, 1);
+       clear_message (true, true);
 
       do_pending_window_change (0);
       echo_area_display (1);
@@ -9857,19 +10214,17 @@ message_with_string (const char *m, Lisp_Object string, int log)
     {
       if (m)
        {
-         /* ENCODE_SYSTEM below can GC and/or relocate the Lisp
-            String whose data pointer might be passed to us in M.  So
-            we use a local copy.  */
-         char *fmt = xstrdup (m);
+         /* ENCODE_SYSTEM below can GC and/or relocate the
+            Lisp data, so make sure we don't use it here.  */
+         eassert (relocatable_string_data_p (m) != 1);
 
          if (noninteractive_need_newline)
            putc ('\n', stderr);
          noninteractive_need_newline = 0;
-         fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string)));
+         fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string)));
          if (!cursor_in_echo_area)
            fprintf (stderr, "\n");
          fflush (stderr);
-         xfree (fmt);
        }
     }
   else if (INTERACTIVE)
@@ -10070,7 +10425,7 @@ with_echo_area_buffer (struct window *w, int which,
 {
   Lisp_Object buffer;
   int this_one, the_other, clear_buffer_p, rc;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   /* If buffers aren't live, make new ones.  */
   ensure_echo_area_buffers ();
@@ -10084,7 +10439,7 @@ with_echo_area_buffer (struct window *w, int which,
   else
     {
       this_one = 0, the_other = 1;
-      clear_buffer_p = 1;
+      clear_buffer_p = true;
 
       /* We need a fresh one in case the current echo buffer equals
         the one containing the last displayed echo area message.  */
@@ -10101,7 +10456,7 @@ with_echo_area_buffer (struct window *w, int which,
        = (EQ (echo_area_buffer[the_other], echo_buffer[this_one])
           ? echo_buffer[the_other]
           : echo_buffer[this_one]);
-      clear_buffer_p = 1;
+      clear_buffer_p = true;
     }
 
   buffer = echo_area_buffer[this_one];
@@ -10144,7 +10499,7 @@ with_echo_area_buffer (struct window *w, int which,
   eassert (BEGV >= BEG);
   eassert (ZV <= Z && ZV >= BEGV);
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return rc;
 }
 
@@ -10249,11 +10604,11 @@ setup_echo_area_for_printing (int multibyte_p)
 
       if (Z > BEG)
        {
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
          specbind (Qinhibit_read_only, Qt);
          /* Note that undo recording is always disabled.  */
          del_range (BEG, Z);
-         unbind_to (count, Qnil);
+         dynwind_end ();
        }
       TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
@@ -10304,13 +10659,6 @@ display_echo_area (struct window *w)
 {
   int i, no_message_p, window_height_changed_p;
 
-  /* Temporarily disable garbage collections while displaying the echo
-     area.  This is done because a GC can print a message itself.
-     That message would modify the echo area buffer's contents while a
-     redisplay of the buffer is going on, and seriously confuse
-     redisplay.  */
-  ptrdiff_t count = inhibit_garbage_collection ();
-
   /* If there is no message, we must call display_echo_area_1
      nevertheless because it resizes the window.  But we will have to
      reset the echo_area_buffer in question to nil at the end because
@@ -10326,7 +10674,6 @@ display_echo_area (struct window *w)
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
 
-  unbind_to (count, Qnil);
   return window_height_changed_p;
 }
 
@@ -10442,11 +10789,10 @@ resize_mini_window (struct window *w, int exact_p)
   if (!FRAME_MINIBUF_ONLY_P (f))
     {
       struct it it;
-      struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
-      int total_height = WINDOW_TOTAL_LINES (root) + WINDOW_TOTAL_LINES (w);
-      int height;
-      EMACS_INT max_height;
+      int total_height = (WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_ROOT_WINDOW (f)))
+                         + WINDOW_PIXEL_HEIGHT (w));
       int unit = FRAME_LINE_HEIGHT (f);
+      int height, max_height;
       struct text_pos start;
       struct buffer *old_current_buffer = NULL;
 
@@ -10460,18 +10806,18 @@ resize_mini_window (struct window *w, int exact_p)
 
       /* Compute the max. number of lines specified by the user.  */
       if (FLOATP (Vmax_mini_window_height))
-       max_height = XFLOATINT (Vmax_mini_window_height) * FRAME_LINES (f);
+       max_height = XFLOATINT (Vmax_mini_window_height) * total_height;
       else if (INTEGERP (Vmax_mini_window_height))
-       max_height = XINT (Vmax_mini_window_height);
+       max_height = XINT (Vmax_mini_window_height) * unit;
       else
        max_height = total_height / 4;
 
       /* Correct that max. height if it's bogus.  */
-      max_height = clip_to_bounds (1, max_height, total_height);
+      max_height = clip_to_bounds (unit, max_height, total_height);
 
       /* Find out the height of the text in the window.  */
       if (it.line_wrap == TRUNCATE)
-       height = 1;
+       height = unit;
       else
        {
          last_height = 0;
@@ -10481,15 +10827,14 @@ resize_mini_window (struct window *w, int exact_p)
          else
            height = it.current_y + it.max_ascent + it.max_descent;
          height -= min (it.extra_line_spacing, it.max_extra_line_spacing);
-         height = (height + unit - 1) / unit;
        }
 
       /* Compute a suitable window start.  */
       if (height > max_height)
        {
-         height = max_height;
+         height = (max_height / unit) * unit;
          init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID);
-         move_it_vertically_backward (&it, (height - 1) * unit);
+         move_it_vertically_backward (&it, height - unit);
          start = it.current.pos;
        }
       else
@@ -10500,49 +10845,49 @@ resize_mini_window (struct window *w, int exact_p)
        {
          /* Let it grow only, until we display an empty message, in which
             case the window shrinks again.  */
-         if (height > WINDOW_TOTAL_LINES (w))
+         if (height > WINDOW_PIXEL_HEIGHT (w))
            {
-             int old_height = WINDOW_TOTAL_LINES (w);
+             int old_height = WINDOW_PIXEL_HEIGHT (w);
 
              FRAME_WINDOWS_FROZEN (f) = 1;
-             grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
-             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+             grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
+             window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
            }
-         else if (height < WINDOW_TOTAL_LINES (w)
+         else if (height < WINDOW_PIXEL_HEIGHT (w)
                   && (exact_p || BEGV == ZV))
            {
-             int old_height = WINDOW_TOTAL_LINES (w);
+             int old_height = WINDOW_PIXEL_HEIGHT (w);
 
              FRAME_WINDOWS_FROZEN (f) = 0;
-             shrink_mini_window (w);
-             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+             shrink_mini_window (w, 1);
+             window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
            }
        }
       else
        {
          /* Always resize to exact size needed.  */
-         if (height > WINDOW_TOTAL_LINES (w))
+         if (height > WINDOW_PIXEL_HEIGHT (w))
            {
-             int old_height = WINDOW_TOTAL_LINES (w);
+             int old_height = WINDOW_PIXEL_HEIGHT (w);
 
              FRAME_WINDOWS_FROZEN (f) = 1;
-             grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
-             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+             grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
+             window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
            }
-         else if (height < WINDOW_TOTAL_LINES (w))
+         else if (height < WINDOW_PIXEL_HEIGHT (w))
            {
-             int old_height = WINDOW_TOTAL_LINES (w);
+             int old_height = WINDOW_PIXEL_HEIGHT (w);
 
              FRAME_WINDOWS_FROZEN (f) = 0;
-             shrink_mini_window (w);
+             shrink_mini_window (w, 1);
 
              if (height)
                {
                  FRAME_WINDOWS_FROZEN (f) = 1;
-                 grow_mini_window (w, height - WINDOW_TOTAL_LINES (w));
+                 grow_mini_window (w, height - WINDOW_PIXEL_HEIGHT (w), 1);
                }
 
-             window_height_changed_p = WINDOW_TOTAL_LINES (w) != old_height;
+             window_height_changed_p = WINDOW_PIXEL_HEIGHT (w) != old_height;
            }
        }
 
@@ -10727,12 +11072,12 @@ set_message_1 (ptrdiff_t a1, Lisp_Object string)
    last displayed.  */
 
 void
-clear_message (int current_p, int last_displayed_p)
+clear_message (bool current_p, bool last_displayed_p)
 {
   if (current_p)
     {
       echo_area_buffer[0] = Qnil;
-      message_cleared_p = 1;
+      message_cleared_p = true;
     }
 
   if (last_displayed_p)
@@ -10814,7 +11159,7 @@ echo_area_display (int update_frame_p)
     {
       echo_area_window = mini_window;
       window_height_changed_p = display_echo_area (w);
-      w->must_be_updated_p = 1;
+      w->must_be_updated_p = true;
 
       /* Update the display, unless called from redisplay_internal.
         Also don't update the screen during redisplay itself.  The
@@ -10830,7 +11175,7 @@ echo_area_display (int update_frame_p)
             been called, so that mode lines above the echo area are
             garbaged.  This looks odd, so we prevent it here.  */
          if (!display_completed)
-           n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), 0);
+           n = redisplay_mode_lines (FRAME_ROOT_WINDOW (f), false);
 
          if (window_height_changed_p
              /* Don't do this if Emacs is shutting down.  Redisplay
@@ -10840,11 +11185,11 @@ echo_area_display (int update_frame_p)
              /* Must update other windows.  Likewise as in other
                 cases, don't let this update be interrupted by
                 pending input.  */
-             ptrdiff_t count = SPECPDL_INDEX ();
+             dynwind_begin ();
              specbind (Qredisplay_dont_pause, Qt);
              windows_or_buffers_changed = 44;
              redisplay_internal ();
-             unbind_to (count, Qnil);
+             dynwind_end ();
            }
          else if (FRAME_WINDOW_P (f) && n == 0)
            {
@@ -11136,7 +11481,7 @@ x_consider_frame_title (Lisp_Object frame)
       char *title;
       ptrdiff_t len;
       struct it it;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
 
       FOR_EACH_FRAME (tail, other_frame)
        {
@@ -11172,7 +11517,7 @@ x_consider_frame_title (Lisp_Object frame)
       display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
       len = MODE_LINE_NOPROP_LEN (title_start);
       title = mode_line_noprop_buf + title_start;
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       /* Set the title only if it's changed.  This avoids consing in
         the common case where it hasn't.  (If it turns out that we've
@@ -11193,6 +11538,12 @@ x_consider_frame_title (Lisp_Object frame)
                              Menu Bars
  ***********************************************************************/
 
+/* Non-zero if we will not redisplay all visible windows.  */
+#define REDISPLAY_SOME_P()                             \
+  ((windows_or_buffers_changed == 0                    \
+    || windows_or_buffers_changed == REDISPLAY_SOME)   \
+   && (update_mode_lines == 0                          \
+       || update_mode_lines == REDISPLAY_SOME))
 
 /* Prepare for redisplay by updating menu-bar item lists when
    appropriate.  This can call eval.  */
@@ -11201,11 +11552,7 @@ static void
 prepare_menu_bars (void)
 {
   bool all_windows = windows_or_buffers_changed || update_mode_lines;
-  bool some_windows
-    = (windows_or_buffers_changed == 0
-       || windows_or_buffers_changed == REDISPLAY_SOME)
-    && (update_mode_lines == 0
-       || update_mode_lines == REDISPLAY_SOME);
+  bool some_windows = REDISPLAY_SOME_P ();
   struct gcpro gcpro1, gcpro2;
   Lisp_Object tooltip_frame;
 
@@ -11233,7 +11580,7 @@ prepare_menu_bars (void)
                }
            }
        }
-      safe_call1 (Vpre_redisplay_function, windows);
+      safe__call1 (true, Vpre_redisplay_function, windows);
     }
 
   /* Update all frame titles based on their buffer names, etc.  We do
@@ -11278,7 +11625,7 @@ prepare_menu_bars (void)
   if (all_windows)
     {
       Lisp_Object tail, frame;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       /* 1 means that update_menu_bar has run its hooks
         so any further calls to update_menu_bar shouldn't do so again.  */
       int menu_bar_hooks_run = 0;
@@ -11334,7 +11681,7 @@ prepare_menu_bars (void)
          UNGCPRO;
        }
 
-      unbind_to (count, Qnil);
+      dynwind_end ();
     }
   else
     {
@@ -11397,7 +11744,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
 
          specbind (Qinhibit_menubar_update, Qt);
 
@@ -11450,7 +11797,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
          w->update_mode_line = 1;
 #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || HAVE_NS || USE_GTK) */
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
          set_buffer_internal_1 (prev);
        }
     }
@@ -11464,11 +11811,6 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
 
 #ifdef HAVE_WINDOW_SYSTEM
 
-/* Tool-bar item index of the item on which a mouse button was pressed
-   or -1.  */
-
-int last_tool_bar_item;
-
 /* Select `frame' temporarily without running all the code in
    do_switch_frame.
    FIXME: Maybe do_switch_frame should be trimmed down similarly
@@ -11494,8 +11836,8 @@ update_tool_bar (struct frame *f, int save_match_data)
 #if defined (USE_GTK) || defined (HAVE_NS)
   int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
 #else
-  int do_update = WINDOWP (f->tool_bar_window)
-    && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
+  int do_update = (WINDOWP (f->tool_bar_window)
+                  && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tool_bar_window)) > 0);
 #endif
 
   if (do_update)
@@ -11519,7 +11861,7 @@ update_tool_bar (struct frame *f, int save_match_data)
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
          Lisp_Object frame, new_tool_bar;
           int new_n_tool_bar;
          struct gcpro gcpro1;
@@ -11575,7 +11917,7 @@ update_tool_bar (struct frame *f, int save_match_data)
 
          UNGCPRO;
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
          set_buffer_internal_1 (prev);
        }
     }
@@ -11765,7 +12107,9 @@ display_tool_bar_line (struct it *it, int height)
   int max_x = it->last_visible_x;
   struct glyph *last;
 
-  prepare_desired_row (row);
+  /* Don't extend on a previously drawn tool bar items (Bug#16058).  */
+  clear_glyph_row (row);
+  row->enabled_p = true;
   row->y = it->current_y;
 
   /* Note that this isn't made use of if the face hasn't a box,
@@ -11877,21 +12221,22 @@ display_tool_bar_line (struct it *it, int height)
 }
 
 
-/* Max tool-bar height.  */
+/* Max tool-bar height.  Basically, this is what makes all other windows
+   disappear when the frame gets too small.  Rethink this!  */
 
 #define MAX_FRAME_TOOL_BAR_HEIGHT(f) \
   ((FRAME_LINE_HEIGHT (f) * FRAME_LINES (f)))
 
-/* Value is the number of screen lines needed to make all tool-bar
-   items of frame F visible.  The number of actual rows needed is
+/* Value is the number of pixels needed to make all tool-bar items of
+   frame F visible.  The actual number of glyph rows needed is
    returned in *N_ROWS if non-NULL.  */
 
 static int
-tool_bar_lines_needed (struct frame *f, int *n_rows)
+tool_bar_height (struct frame *f, int *n_rows, bool pixelwise)
 {
   struct window *w = XWINDOW (f->tool_bar_window);
   struct it it;
-  /* tool_bar_lines_needed is called from redisplay_tool_bar after building
+  /* tool_bar_height is called from redisplay_tool_bar after building
      the desired matrix, so use (unused) mode-line row as temporary row to
      avoid destroying the first tool-bar row.  */
   struct glyph_row *temp_row = MATRIX_MODE_LINE_ROW (w->desired_matrix);
@@ -11900,7 +12245,7 @@ tool_bar_lines_needed (struct frame *f, int *n_rows)
      F->desired_tool_bar_string in the tool-bar window of frame F.  */
   init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
   it.first_visible_x = 0;
-  it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+  it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
   reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
   it.paragraph_embedding = L2R;
 
@@ -11916,39 +12261,39 @@ tool_bar_lines_needed (struct frame *f, int *n_rows)
   if (n_rows)
     *n_rows = it.vpos > 0 ? it.vpos : -1;
 
-  return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
+  if (pixelwise)
+    return it.current_y;
+  else
+    return (it.current_y + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
 }
 
 #endif /* !USE_GTK && !HAVE_NS */
 
-#if defined USE_GTK || defined HAVE_NS
-EXFUN (Ftool_bar_lines_needed, 1) ATTRIBUTE_CONST;
-#endif
-
-DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
-       0, 1, 0,
+DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height,
+       0, 2, 0,
        doc: /* Return the number of lines occupied by the tool bar of FRAME.
-If FRAME is nil or omitted, use the selected frame.  */)
-  (Lisp_Object frame)
+If FRAME is nil or omitted, use the selected frame.  Optional argument
+PIXELWISE non-nil means return the height of the tool bar in pixels.  */)
+  (Lisp_Object frame, Lisp_Object pixelwise)
 {
-  int nlines = 0;
+  int height = 0;
+
 #if ! defined (USE_GTK) && ! defined (HAVE_NS)
   struct frame *f = decode_any_frame (frame);
-  struct window *w;
 
   if (WINDOWP (f->tool_bar_window)
-      && (w = XWINDOW (f->tool_bar_window),
-         WINDOW_TOTAL_LINES (w) > 0))
+      && WINDOW_PIXEL_HEIGHT (XWINDOW (f->tool_bar_window)) > 0)
     {
       update_tool_bar (f, 1);
       if (f->n_tool_bar_items)
        {
          build_desired_tool_bar_string (f);
-         nlines = tool_bar_lines_needed (f, NULL);
+         height = tool_bar_height (f, NULL, NILP (pixelwise) ? 0 : 1);
        }
     }
 #endif
-  return make_number (nlines);
+
+  return make_number (height);
 }
 
 
@@ -11976,13 +12321,13 @@ redisplay_tool_bar (struct frame *f)
      can turn off tool-bars by specifying tool-bar-lines zero.  */
   if (!WINDOWP (f->tool_bar_window)
       || (w = XWINDOW (f->tool_bar_window),
-          WINDOW_TOTAL_LINES (w) == 0))
+          WINDOW_PIXEL_HEIGHT (w) == 0))
     return 0;
 
   /* Set up an iterator for the tool-bar window.  */
   init_iterator (&it, w, -1, -1, w->desired_matrix->rows, TOOL_BAR_FACE_ID);
   it.first_visible_x = 0;
-  it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+  it.last_visible_x = WINDOW_PIXEL_WIDTH (w);
   row = it.glyph_row;
 
   /* Build a string that represents the contents of the tool-bar.  */
@@ -11999,24 +12344,22 @@ redisplay_tool_bar (struct frame *f)
 
   if (f->n_tool_bar_rows == 0)
     {
-      int nlines;
+      int new_height = tool_bar_height (f, &f->n_tool_bar_rows, 1);
 
-      if ((nlines = tool_bar_lines_needed (f, &f->n_tool_bar_rows),
-          nlines != WINDOW_TOTAL_LINES (w)))
+      if (new_height != WINDOW_PIXEL_HEIGHT (w))
        {
          Lisp_Object frame;
-         int old_height = WINDOW_TOTAL_LINES (w);
+         int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1)
+                          / FRAME_LINE_HEIGHT (f));
 
          XSETFRAME (frame, f);
          Fmodify_frame_parameters (frame,
                                    list1 (Fcons (Qtool_bar_lines,
-                                                 make_number (nlines))));
-         if (WINDOW_TOTAL_LINES (w) != old_height)
-           {
-             clear_glyph_matrix (w->desired_matrix);
-             f->fonts_changed = 1;
-             return 1;
-           }
+                                                 make_number (new_lines))));
+         /* Always do that now.  */
+         clear_glyph_matrix (w->desired_matrix);
+         f->fonts_changed = 1;
+         return 1;
        }
     }
 
@@ -12065,6 +12408,7 @@ redisplay_tool_bar (struct frame *f)
 
   if (!NILP (Vauto_resize_tool_bars))
     {
+      /* Do we really allow the toolbar to occupy the whole frame?  */
       int max_tool_bar_height = MAX_FRAME_TOOL_BAR_HEIGHT (f);
       int change_height_p = 0;
 
@@ -12074,6 +12418,10 @@ redisplay_tool_bar (struct frame *f)
          && it.current_y < max_tool_bar_height)
        change_height_p = 1;
 
+      /* We subtract 1 because display_tool_bar_line advances the
+        glyph_row pointer before returning to its caller.  We want to
+        examine the last glyph row produced by
+        display_tool_bar_line.  */
       row = it.glyph_row - 1;
 
       /* If there are blank lines at the end, except for a partially
@@ -12095,24 +12443,41 @@ redisplay_tool_bar (struct frame *f)
       if (change_height_p)
        {
          Lisp_Object frame;
-         int old_height = WINDOW_TOTAL_LINES (w);
          int nrows;
-         int nlines = tool_bar_lines_needed (f, &nrows);
+         int new_height = tool_bar_height (f, &nrows, 1);
 
          change_height_p = ((EQ (Vauto_resize_tool_bars, Qgrow_only)
                              && !f->minimize_tool_bar_window_p)
-                            ? (nlines > old_height)
-                            : (nlines != old_height));
+                            ? (new_height > WINDOW_PIXEL_HEIGHT (w))
+                            : (new_height != WINDOW_PIXEL_HEIGHT (w)));
          f->minimize_tool_bar_window_p = 0;
 
          if (change_height_p)
            {
-             XSETFRAME (frame, f);
-             Fmodify_frame_parameters (frame,
-                                       list1 (Fcons (Qtool_bar_lines,
-                                                     make_number (nlines))));
-             if (WINDOW_TOTAL_LINES (w) != old_height)
+             /* Current size of the tool-bar window in canonical line
+                units.  */
+             int old_lines = WINDOW_TOTAL_LINES (w);
+             /* Required size of the tool-bar window in canonical
+                line units. */
+             int new_lines = ((new_height + FRAME_LINE_HEIGHT (f) - 1)
+                              / FRAME_LINE_HEIGHT (f));
+             /* Maximum size of the tool-bar window in canonical line
+                units that this frame can allow. */
+             int max_lines =
+               WINDOW_TOTAL_LINES (XWINDOW (FRAME_ROOT_WINDOW (f))) - 1;
+
+             /* Don't try to change the tool-bar window size and set
+                the fonts_changed flag unless really necessary.  That
+                flag causes redisplay to give up and retry
+                redisplaying the frame from scratch, so setting it
+                unnecessarily can lead to nasty redisplay loops.  */
+             if (new_lines <= max_lines
+                 && eabs (new_lines - old_lines) >= 1)
                {
+                 XSETFRAME (frame, f);
+                 Fmodify_frame_parameters (frame,
+                                           list1 (Fcons (Qtool_bar_lines,
+                                                         make_number (new_lines))));
                  clear_glyph_matrix (w->desired_matrix);
                  f->n_tool_bar_rows = nrows;
                  f->fonts_changed = 1;
@@ -12242,7 +12607,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
      where the button was pressed, disregarding where it was
      released.  */
   if (NILP (Vmouse_highlight) && !down_p)
-    prop_idx = last_tool_bar_item;
+    prop_idx = f->last_tool_bar_item;
 
   /* If item is disabled, do nothing.  */
   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
@@ -12254,7 +12619,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       /* Show item in pressed state.  */
       if (!NILP (Vmouse_highlight))
        show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
-      last_tool_bar_item = prop_idx;
+      f->last_tool_bar_item = prop_idx;
     }
   else
     {
@@ -12279,7 +12644,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       event.arg = key;
       event.modifiers = modifiers;
       kbd_buffer_store_event (&event);
-      last_tool_bar_item = -1;
+      f->last_tool_bar_item = -1;
     }
 }
 
@@ -12329,8 +12694,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
   mouse_down_p = (x_mouse_grabbed (dpyinfo)
                  && f == dpyinfo->last_mouse_frame);
 
-  if (mouse_down_p
-      && last_tool_bar_item != prop_idx)
+  if (mouse_down_p && f->last_tool_bar_item != prop_idx)
     return;
 
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
@@ -12427,15 +12791,25 @@ hscroll_window_tree (Lisp_Object window)
        {
          int h_margin;
          int text_area_width;
-         struct glyph_row *current_cursor_row
-           = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
-         struct glyph_row *desired_cursor_row
-           = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
-         struct glyph_row *cursor_row
-           = (desired_cursor_row->enabled_p
-              ? desired_cursor_row
-              : current_cursor_row);
-         int row_r2l_p = cursor_row->reversed_p;
+         struct glyph_row *cursor_row;
+         struct glyph_row *bottom_row;
+         int row_r2l_p;
+
+         bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->desired_matrix, w);
+         if (w->cursor.vpos < bottom_row - w->desired_matrix->rows)
+           cursor_row = MATRIX_ROW (w->desired_matrix, w->cursor.vpos);
+         else
+           cursor_row = bottom_row - 1;
+
+         if (!cursor_row->enabled_p)
+           {
+             bottom_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+             if (w->cursor.vpos < bottom_row - w->current_matrix->rows)
+               cursor_row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+             else
+               cursor_row = bottom_row - 1;
+           }
+         row_r2l_p = cursor_row->reversed_p;
 
          text_area_width = window_box_width (w, TEXT_AREA);
 
@@ -12446,7 +12820,7 @@ hscroll_window_tree (Lisp_Object window)
              /* For left-to-right rows, hscroll when cursor is either
                 (i) inside the right hscroll margin, or (ii) if it is
                 inside the left margin and the window is already
-                hscrolled. */
+                hscrolled.  */
              && ((!row_r2l_p
                   && ((w->hscroll
                        && w->cursor.x <= h_margin)
@@ -12463,7 +12837,7 @@ hscroll_window_tree (Lisp_Object window)
                      && ((cursor_row->enabled_p
                           /* FIXME: It is confusing to set the
                              truncated_on_right_p flag when R2L rows
-                             are actually truncated on the left. */
+                             are actually truncated on the left.  */
                           && cursor_row->truncated_on_right_p
                           && w->cursor.x <= h_margin)
                          || (w->hscroll
@@ -12591,7 +12965,7 @@ static ptrdiff_t debug_delta, debug_delta_bytes;
 static ptrdiff_t debug_end_vpos;
 
 /* Append a string to W->desired_matrix->method.  FMT is a printf
-   format string.  If trace_redisplay_p is non-zero also printf the
+   format string.  If trace_redisplay_p is true also printf the
    resulting string to stderr.  */
 
 static void debug_method_add (struct window *, char const *, ...)
@@ -12922,7 +13296,8 @@ reconsider_clip_changes (struct window *w)
     }
 }
 
-void propagate_buffer_redisplay (void)
+static void
+propagate_buffer_redisplay (void)
 { /* Resetting b->text->redisplay is problematic!
      We can't just reset it in the case that some window that displays
      it has not been redisplayed; and such a window can stay
@@ -12943,15 +13318,6 @@ void propagate_buffer_redisplay (void)
     }
 }
 
-#define STOP_POLLING                                   \
-do { if (! polling_stopped_here) stop_polling ();      \
-       polling_stopped_here = 1; } while (0)
-
-#define RESUME_POLLING                                 \
-do { if (polling_stopped_here) start_polling ();       \
-       polling_stopped_here = 0; } while (0)
-
-
 /* Perhaps in the future avoid recentering windows if it
    is not necessary; currently that causes some problems.  */
 
@@ -13006,13 +13372,13 @@ redisplay_internal (void)
 
   /* Record a function that clears redisplaying_p
      when we leave this function.  */
-  count = SPECPDL_INDEX ();
+  dynwind_begin ();
   record_unwind_protect_void (unwind_redisplay);
   redisplaying_p = 1;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
   /* Record this function, so it appears on the profiler's backtraces.  */
-  record_in_backtrace (Qredisplay_internal, &Qnil, 0);
+  /*record_in_backtrace (Qredisplay_internal, &Qnil, 0);*/
 
   FOR_EACH_FRAME (tail, frame)
     XFRAME (frame)->already_hscrolled_p = 0;
@@ -13315,6 +13681,8 @@ redisplay_internal (void)
               PT == w->last_point
               /* Make sure the cursor was last displayed
                  in this window.  Otherwise we have to reposition it.  */
+
+              /* PXW: Must be converted to pixels, probably.  */
               && 0 <= w->cursor.vpos
               && w->cursor.vpos < WINDOW_TOTAL_LINES (w))
        {
@@ -13373,7 +13741,7 @@ redisplay_internal (void)
 
     cancel:
       /* Text changed drastically or point moved off of line.  */
-      SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, 0);
+      SET_MATRIX_ROW_ENABLED_P (w->desired_matrix, this_line_vpos, false);
     }
 
   CHARPOS (this_line_start_pos) = 0;
@@ -13408,8 +13776,8 @@ redisplay_internal (void)
          if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
            {
              bool gcscrollbars
-               /* Only GC scollbars when we redisplay the whole frame.  */
-               = f->redisplay || windows_or_buffers_changed != REDISPLAY_SOME;
+               /* Only GC scrollbars when we redisplay the whole frame.  */
+               = f->redisplay || !REDISPLAY_SOME_P ();
              /* Mark all the scroll bars to be removed; we'll redeem
                 the ones we want when we redisplay their windows.  */
              if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
@@ -13417,6 +13785,10 @@ redisplay_internal (void)
 
              if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
                redisplay_windows (FRAME_ROOT_WINDOW (f));
+             /* Remember that the invisible frames need to be redisplayed next
+                time they're visible.  */
+             else if (!REDISPLAY_SOME_P ())
+               f->redisplay = true;
 
              /* The X error handler may have deleted that frame.  */
              if (!FRAME_LIVE_P (f))
@@ -13445,21 +13817,6 @@ redisplay_internal (void)
                        goto retry_frame;
                    }
 
-                 /* Prevent various kinds of signals during display
-                    update.  stdio is not robust about handling
-                    signals, which can cause an apparent I/O
-                    error.  */
-                 if (interrupt_input)
-                   unrequest_sigio ();
-                 STOP_POLLING;
-
-                 /* Mark windows on frame F to update.  If we decide to
-                    update all frames but windows_or_buffers_changed is
-                    zero, we assume that only the windows that shows
-                    current buffer should be really updated.  */
-                 set_window_update_flags
-                   (XWINDOW (f->root_window),
-                    (windows_or_buffers_changed ? NULL : current_buffer), 1);
                  pending |= update_frame (f, 0, 0);
                  f->cursor_type_changed = 0;
                  f->updated_p = 1;
@@ -13510,19 +13867,12 @@ redisplay_internal (void)
       if (sf->fonts_changed)
        goto retry;
 
-      /* Prevent various kinds of signals during display update.
-        stdio is not robust about handling signals,
-        which can cause an apparent I/O error.  */
-      if (interrupt_input)
-       unrequest_sigio ();
-      STOP_POLLING;
-
       if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
        {
          if (hscroll_windows (selected_window))
            goto retry;
 
-         XWINDOW (selected_window)->must_be_updated_p = 1;
+         XWINDOW (selected_window)->must_be_updated_p = true;
          pending = update_frame (sf, 0, 0);
          sf->cursor_type_changed = 0;
        }
@@ -13537,7 +13887,7 @@ redisplay_internal (void)
 
       if (mini_frame != sf && FRAME_WINDOW_P (mini_frame))
        {
-         XWINDOW (mini_window)->must_be_updated_p = 1;
+         XWINDOW (mini_window)->must_be_updated_p = true;
          pending |= update_frame (mini_frame, 0, 0);
          mini_frame->cursor_type_changed = 0;
          if (!pending && hscroll_windows (mini_window))
@@ -13587,14 +13937,6 @@ redisplay_internal (void)
       windows_or_buffers_changed = 0;
     }
 
-  /* Start SIGIO interrupts coming again.  Having them off during the
-     code above makes it less likely one will discard output, but not
-     impossible, since there might be stuff in the system buffer here.
-     But it is much hairier to try to do anything about that.  */
-  if (interrupt_input)
-    request_sigio ();
-  RESUME_POLLING;
-
   /* If a frame has become visible which was not before, redisplay
      again, so that we display it.  Expose events for such a frame
      (which it gets when becoming visible) don't call the parts of
@@ -13645,8 +13987,7 @@ redisplay_internal (void)
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
-  unbind_to (count, Qnil);
-  RESUME_POLLING;
+  dynwind_end ();
 }
 
 
@@ -13838,7 +14179,7 @@ static Lisp_Object
 redisplay_window_0 (Lisp_Object window)
 {
   if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
-    redisplay_window (window, 0);
+    redisplay_window (window, false);
   return Qnil;
 }
 
@@ -13846,7 +14187,7 @@ static Lisp_Object
 redisplay_window_1 (Lisp_Object window)
 {
   if (displayed_buffer->display_error_modiff < BUF_MODIFF (displayed_buffer))
-    redisplay_window (window, 1);
+    redisplay_window (window, true);
   return Qnil;
 }
 \f
@@ -14037,7 +14378,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
-                 bpos_max = prop_pos - 1;
+                 bpos_max = prop_pos;
              }
            if (INTEGERP (chprop))
              {
@@ -14111,7 +14452,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
-                 bpos_max = prop_pos - 1;
+                 bpos_max = prop_pos;
              }
            if (INTEGERP (chprop))
              {
@@ -14141,7 +14482,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
      GLYPH_BEFORE and GLYPH_AFTER.  */
   if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
        && BUFFERP (glyph->object) && glyph->charpos == pt_old)
-      && !(bpos_max < pt_old && pt_old <= bpos_covered))
+      && !(bpos_max <= pt_old && pt_old <= bpos_covered))
     {
       /* An empty line has a single glyph whose OBJECT is zero and
         whose CHARPOS is the position of a newline on that line.
@@ -14867,7 +15208,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
       if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0)
          /* It's possible that the cursor is on the first line of the
             buffer, which is partially obscured due to a vscroll
-            (Bug#7537).  In that case, avoid looping forever . */
+            (Bug#7537).  In that case, avoid looping forever. */
          && extra_scroll_margin_lines < w->desired_matrix->nrows - 1)
        {
          clear_glyph_matrix (w->desired_matrix);
@@ -14922,6 +15263,7 @@ compute_window_start_on_continuation_line (struct window *w)
       /* If the line start is "too far" away from the window start,
          say it takes too much time to compute a new window start.  */
       if (CHARPOS (start_pos) - IT_CHARPOS (it)
+         /* PXW: Do we need upper bounds here?  */
          < WINDOW_TOTAL_LINES (w) * WINDOW_TOTAL_COLS (w))
        {
          int min_distance, distance;
@@ -15259,29 +15601,32 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
                  /* As soon as we've found the exact match for point,
                     or the first suitable row whose ends_at_zv_p flag
                     is set, we are done.  */
-                 at_zv_p =
-                   MATRIX_ROW (w->current_matrix, w->cursor.vpos)->ends_at_zv_p;
-                 if (rv && !at_zv_p
-                     && w->cursor.hpos >= 0
-                     && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix,
-                                                          w->cursor.vpos))
-                   {
-                     struct glyph_row *candidate =
-                       MATRIX_ROW (w->current_matrix, w->cursor.vpos);
-                     struct glyph *g =
-                       candidate->glyphs[TEXT_AREA] + w->cursor.hpos;
-                     ptrdiff_t endpos = MATRIX_ROW_END_CHARPOS (candidate);
-
-                     exact_match_p =
-                       (BUFFERP (g->object) && g->charpos == PT)
-                       || (INTEGERP (g->object)
-                           && (g->charpos == PT
-                               || (g->charpos == 0 && endpos - 1 == PT)));
-                   }
-                 if (rv && (at_zv_p || exact_match_p))
+                 if (rv)
                    {
-                     rc = CURSOR_MOVEMENT_SUCCESS;
-                     break;
+                     at_zv_p = MATRIX_ROW (w->current_matrix,
+                                           w->cursor.vpos)->ends_at_zv_p;
+                     if (!at_zv_p
+                         && w->cursor.hpos >= 0
+                         && w->cursor.hpos < MATRIX_ROW_USED (w->current_matrix,
+                                                              w->cursor.vpos))
+                       {
+                         struct glyph_row *candidate =
+                           MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+                         struct glyph *g =
+                           candidate->glyphs[TEXT_AREA] + w->cursor.hpos;
+                         ptrdiff_t endpos = MATRIX_ROW_END_CHARPOS (candidate);
+
+                         exact_match_p =
+                           (BUFFERP (g->object) && g->charpos == PT)
+                           || (INTEGERP (g->object)
+                               && (g->charpos == PT
+                                   || (g->charpos == 0 && endpos - 1 == PT)));
+                       }
+                     if (at_zv_p || exact_match_p)
+                       {
+                         rc = CURSOR_MOVEMENT_SUCCESS;
+                         break;
+                       }
                    }
                  if (MATRIX_ROW_BOTTOM_Y (row) == last_y)
                    break;
@@ -15324,9 +15669,6 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
   return rc;
 }
 
-#if !defined USE_TOOLKIT_SCROLL_BARS || defined USE_GTK
-static
-#endif
 void
 set_vertical_scroll_bar (struct window *w)
 {
@@ -15369,10 +15711,54 @@ set_vertical_scroll_bar (struct window *w)
    selected_window is redisplayed.
 
    We can return without actually redisplaying the window if fonts has been
-   changed on window's frame.  In that case, redisplay_internal will retry.  */
+   changed on window's frame.  In that case, redisplay_internal will retry.
+
+   As one of the important parts of redisplaying a window, we need to
+   decide whether the previous window-start position (stored in the
+   window's w->start marker position) is still valid, and if it isn't,
+   recompute it.  Some details about that:
+
+    . The previous window-start could be in a continuation line, in
+      which case we need to recompute it when the window width
+      changes.  See compute_window_start_on_continuation_line and its
+      call below.
+
+    . The text that changed since last redisplay could include the
+      previous window-start position.  In that case, we try to salvage
+      what we can from the current glyph matrix by calling
+      try_scrolling, which see.
+
+    . Some Emacs command could force us to use a specific window-start
+      position by setting the window's force_start flag, or gently
+      propose doing that by setting the window's optional_new_start
+      flag.  In these cases, we try using the specified start point if
+      that succeeds (i.e. the window desired matrix is successfully
+      recomputed, and point location is within the window).  In case
+      of optional_new_start, we first check if the specified start
+      position is feasible, i.e. if it will allow point to be
+      displayed in the window.  If using the specified start point
+      fails, e.g., if new fonts are needed to be loaded, we abort the
+      redisplay cycle and leave it up to the next cycle to figure out
+      things.
+
+    . Note that the window's force_start flag is sometimes set by
+      redisplay itself, when it decides that the previous window start
+      point is fine and should be kept.  Search for "goto force_start"
+      below to see the details.  Like the values of window-start
+      specified outside of redisplay, these internally-deduced values
+      are tested for feasibility, and ignored if found to be
+      unfeasible.
+
+    . Note that the function try_window, used to completely redisplay
+      a window, accepts the window's start point as its argument.
+      This is used several times in the redisplay code to control
+      where the window start will be, according to user options such
+      as scroll-conservatively, and also to ensure the screen line
+      showing point will be fully (as opposed to partially) visible on
+      display.  */
 
 static void
-redisplay_window (Lisp_Object window, int just_this_one_p)
+redisplay_window (Lisp_Object window, bool just_this_one_p)
 {
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
@@ -15383,13 +15769,12 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   int tem;
   struct it it;
   /* Record it now because it's overwritten.  */
-  int current_matrix_up_to_date_p = 0;
-  int used_current_matrix_p = 0;
+  bool current_matrix_up_to_date_p = false;
+  bool used_current_matrix_p = false;
   /* This is less strict than current_matrix_up_to_date_p.
      It indicates that the buffer contents and narrowing are unchanged.  */
-  int buffer_unchanged_p = 0;
+  bool buffer_unchanged_p = false;
   int temp_scroll_step = 0;
-  ptrdiff_t count = SPECPDL_INDEX ();
   int rc;
   int centering_position = -1;
   int last_line_misfit = 0;
@@ -15404,19 +15789,21 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 #endif
 
   if (!just_this_one_p
-      && (update_mode_lines == REDISPLAY_SOME
-         || update_mode_lines == 0)
-      && (windows_or_buffers_changed == REDISPLAY_SOME
-         || windows_or_buffers_changed == 0)
+      && REDISPLAY_SOME_P ()
       && !w->redisplay
       && !f->redisplay
-      && !buffer->text->redisplay)
+      && !buffer->text->redisplay
+      && BUF_PT (buffer) == w->last_point)
     return;
 
   /* Make sure that both W's markers are valid.  */
   eassert (XMARKER (w->start)->buffer == buffer);
   eassert (XMARKER (w->pointm)->buffer == buffer);
 
+  dynwind_begin ();
+
+  /* We come here again if we need to run window-text-change-functions
+     below.  */
  restart:
   reconsider_clip_changes (w);
   frame_line_height = default_line_pixel_height (w);
@@ -15427,6 +15814,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
                      || buffer->clip_changed
                      || buffer->prevent_redisplay_optimizations_p);
 
+  if (!just_this_one_p)
+    /* If `just_this_one_p' is set, we apparently set must_be_updated_p more
+       cleverly elsewhere.  */
+    w->must_be_updated_p = true;
+
   if (MINI_WINDOW_P (w))
     {
       if (w == XWINDOW (echo_area_window)
@@ -15476,7 +15868,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        && !current_buffer->prevent_redisplay_optimizations_p
        && !window_outdated (w));
 
-  /* Run the window-bottom-change-functions
+  /* Run the window-text-change-functions
      if it is possible that the text on the screen has changed
      (either due to modification of the text, or any other reason).  */
   if (!current_matrix_up_to_date_p
@@ -15507,10 +15899,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       if (XMARKER (w->start)->buffer == current_buffer)
        compute_window_start_on_continuation_line (w);
 
-      w->window_end_valid = 0;
+      w->window_end_valid = false;
       /* 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;
+      current_matrix_up_to_date_p = false;
     }
 
   /* Some sanity checks.  */
@@ -15551,16 +15943,20 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
      this may be a bit late to catch such changes, but the rest of
      redisplay goes (non-fatally) haywire when the display table is
      changed, so why should we worry about doing any better?  */
-  if (current_buffer->width_run_cache)
+  if (current_buffer->width_run_cache
+      || (current_buffer->base_buffer
+         && current_buffer->base_buffer->width_run_cache))
     {
       struct Lisp_Char_Table *disptab = buffer_display_table ();
 
       if (! disptab_matches_widthtab
          (disptab, XVECTOR (BVAR (current_buffer, width_table))))
         {
-          invalidate_region_cache (current_buffer,
-                                   current_buffer->width_run_cache,
-                                   BEG, Z);
+         struct buffer *buf = current_buffer;
+
+         if (buf->base_buffer)
+           buf = buf->base_buffer;
+          invalidate_region_cache (buf, buf->width_run_cache, BEG, Z);
           recompute_width_table (current_buffer, disptab);
         }
     }
@@ -16073,12 +16469,50 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   /* Consider the following case: Window starts at BEGV, there is
      invisible, intangible text at BEGV, so that display starts at
      some point START > BEGV.  It can happen that we are called with
-     PT somewhere between BEGV and START.  Try to handle that case.  */
+     PT somewhere between BEGV and START.  Try to handle that case,
+     and similar ones.  */
   if (w->cursor.vpos < 0)
     {
-      struct glyph_row *row = w->current_matrix->rows;
-      if (row->mode_line_p)
-       ++row;
+      /* First, try locating the proper glyph row for PT.  */
+      struct glyph_row *row =
+       row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0);
+
+      /* Sometimes point is at the beginning of invisible text that is
+        before the 1st character displayed in the row.  In that case,
+        row_containing_pos fails to find the row, because no glyphs
+        with appropriate buffer positions are present in the row.
+        Therefore, we next try to find the row which shows the 1st
+        position after the invisible text.  */
+      if (!row)
+       {
+         Lisp_Object val =
+           get_char_property_and_overlay (make_number (PT), Qinvisible,
+                                          Qnil, NULL);
+
+         if (TEXT_PROP_MEANS_INVISIBLE (val))
+           {
+             ptrdiff_t alt_pos;
+             Lisp_Object invis_end =
+               Fnext_single_char_property_change (make_number (PT), Qinvisible,
+                                                  Qnil, Qnil);
+
+             if (NATNUMP (invis_end))
+               alt_pos = XFASTINT (invis_end);
+             else
+               alt_pos = ZV;
+             row = row_containing_pos (w, alt_pos, w->current_matrix->rows,
+                                       NULL, 0);
+           }
+       }
+      /* Finally, fall back on the first row of the window after the
+        header line (if any).  This is slightly better than not
+        displaying the cursor at all.  */
+      if (!row)
+       {
+         row = w->current_matrix->rows;
+         if (row->mode_line_p)
+           ++row;
+       }
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
@@ -16128,7 +16562,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
   SET_TEXT_POS_FROM_MARKER (startp, w->start);
   w->start_at_line_beg = (CHARPOS (startp) == BEGV
-                           || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
+                         || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
 
   /* Display the mode line, if we must.  */
   if ((update_mode_line
@@ -16148,6 +16582,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       && (WINDOW_WANTS_MODELINE_P (w)
          || WINDOW_WANTS_HEADER_LINE_P (w)))
     {
+
       display_mode_lines (w);
 
       /* If mode line height has changed, arrange for a thorough
@@ -16213,7 +16648,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
            redisplay_tool_bar (f);
 #else
          if (WINDOWP (f->tool_bar_window)
-             && (FRAME_TOOL_BAR_LINES (f) > 0
+             && (FRAME_TOOL_BAR_HEIGHT (f) > 0
                  || !NILP (Vauto_resize_tool_bars))
              && redisplay_tool_bar (f))
            ignore_mouse_drag_p = 1;
@@ -16231,10 +16666,18 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
       update_begin (f);
       block_input ();
       if (draw_window_fringes (w, 1))
-       x_draw_vertical_border (w);
+       {
+         if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+           x_draw_right_divider (w);
+         else
+           x_draw_vertical_border (w);
+       }
       unblock_input ();
       update_end (f);
     }
+
+  if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+    x_draw_bottom_divider (w);
 #endif /* HAVE_WINDOW_SYSTEM */
 
   /* We go to this label, with fonts_changed set, if it is
@@ -16268,11 +16711,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
   set_buffer_internal_1 (old);
   /* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become
-     shorter.  This can be caused by log truncation in *Messages*. */
+     shorter.  This can be caused by log truncation in *Messages*.  */
   if (CHARPOS (lpoint) <= ZV)
     TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 
@@ -16548,7 +16991,7 @@ try_window_reusing_current_matrix (struct window *w)
 
          /* Disable lines that must be updated.  */
          for (i = 0; i < nrows_scrolled; ++i)
-           (start_row + i)->enabled_p = 0;
+           (start_row + i)->enabled_p = false;
 
          /* Re-compute Y positions.  */
          min_y = WINDOW_HEADER_LINE_HEIGHT (w);
@@ -16728,7 +17171,7 @@ try_window_reusing_current_matrix (struct window *w)
 
       /* Disable rows not reused.  */
       for (row -= nrows_scrolled; row < bottom_row; ++row)
-       row->enabled_p = 0;
+       row->enabled_p = false;
 
       /* Point may have moved to a different line, so we cannot assume that
         the previous cursor position is valid; locate the correct row.  */
@@ -17013,7 +17456,7 @@ sync_frame_with_window_matrix_rows (struct window *w)
       /* Disable frame rows whose corresponding window rows have
         been disabled in try_window_id.  */
       if (!window_row->enabled_p)
-       frame_row->enabled_p = 0;
+       frame_row->enabled_p = false;
 
       ++window_row, ++frame_row;
     }
@@ -17103,9 +17546,16 @@ row_containing_pos (struct window *w, ptrdiff_t charpos,
 
    Value is
 
-   1   if display has been updated
-   0   if otherwise unsuccessful
+   >= 1        if successful, i.e. display has been updated
+         specifically:
+         1 means the changes were in front of a newline that precedes
+           the window start, and the whole current matrix was reused
+         2 means the changes were after the last position displayed
+           in the window, and the whole current matrix was reused
+         3 means portions of the current matrix were reused, while
+           some of the screen lines were redrawn
    -1  if redisplay with same window start is known not to succeed
+   0   if otherwise unsuccessful
 
    The following steps are performed:
 
@@ -17180,6 +17630,12 @@ try_window_id (struct window *w)
   if (windows_or_buffers_changed || f->cursor_type_changed)
     GIVE_UP (2);
 
+  /* This function's optimizations cannot be used if overlays have
+     changed in the buffer displayed by the window, so give up if they
+     have.  */
+  if (w->last_overlay_modified != OVERLAY_MODIFF)
+    GIVE_UP (21);
+
   /* Verify that narrowing has not changed.
      Also verify that we were not told to prevent redisplay optimizations.
      It would be nice to further
@@ -17529,7 +17985,7 @@ try_window_id (struct window *w)
        = run.current_y = run.desired_y = run.height = 0;
       first_unchanged_at_end_row = NULL;
     }
-  IF_DEBUG (debug_dvpos = dvpos; debug_dy = dy);
+  IF_DEBUG ((debug_dvpos = dvpos, debug_dy = dy));
 
 
   /* Find the cursor if not already found.  We have to decide whether
@@ -17756,7 +18212,7 @@ try_window_id (struct window *w)
             the current matrix?  I don't think so, so we mark rows
             displayed invalid in the current matrix by setting their
             enabled_p flag to zero.  */
-         MATRIX_ROW (w->current_matrix, it.vpos)->enabled_p = 0;
+         SET_MATRIX_ROW_ENABLED_P (w->current_matrix, it.vpos, false);
          if (display_line (&it))
            last_text_row_at_end = it.glyph_row - 1;
        }
@@ -17825,8 +18281,8 @@ try_window_id (struct window *w)
   else
     emacs_abort ();
 
-  IF_DEBUG (debug_end_pos = w->window_end_pos;
-           debug_end_vpos = 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;
@@ -18267,6 +18723,7 @@ insert_left_trunc_glyphs (struct it *it)
   truncate_it.current_x = 0;
   truncate_it.face_id = DEFAULT_FACE_ID;
   truncate_it.glyph_row = &scratch_glyph_row;
+  truncate_it.area = TEXT_AREA;
   truncate_it.glyph_row->used[TEXT_AREA] = 0;
   CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
   truncate_it.object = make_number (0);
@@ -18614,10 +19071,14 @@ extend_face_to_end_of_line (struct it *it)
      1-``pixel'' wide, so they hit the equality too early.  This grace
      is needed only for R2L rows that are not continued, to produce
      one extra blank where we could display the cursor.  */
-  if (it->current_x >= it->last_visible_x
-      + (!FRAME_WINDOW_P (f)
-        && it->glyph_row->reversed_p
-        && !it->glyph_row->continued_p))
+  if ((it->current_x >= it->last_visible_x
+       + (!FRAME_WINDOW_P (f)
+         && it->glyph_row->reversed_p
+         && !it->glyph_row->continued_p))
+      /* If the window has display margins, we will need to extend
+        their face even if the text area is filled.  */
+      && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+          || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0))
     return;
 
   /* The default face, possibly remapped. */
@@ -18665,6 +19126,32 @@ extend_face_to_end_of_line (struct it *it)
          it->glyph_row->glyphs[TEXT_AREA][0].face_id = face->id;
          it->glyph_row->used[TEXT_AREA] = 1;
        }
+      /* Mode line and the header line don't have margins, and
+        likewise the frame's tool-bar window, if there is any.  */
+      if (!(it->glyph_row->mode_line_p
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
+           || (WINDOWP (f->tool_bar_window)
+               && it->w == XWINDOW (f->tool_bar_window))
+#endif
+           ))
+       {
+         if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+             && it->glyph_row->used[LEFT_MARGIN_AREA] == 0)
+           {
+             it->glyph_row->glyphs[LEFT_MARGIN_AREA][0] = space_glyph;
+             it->glyph_row->glyphs[LEFT_MARGIN_AREA][0].face_id =
+               default_face->id;
+             it->glyph_row->used[LEFT_MARGIN_AREA] = 1;
+           }
+         if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+             && it->glyph_row->used[RIGHT_MARGIN_AREA] == 0)
+           {
+             it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0] = space_glyph;
+             it->glyph_row->glyphs[RIGHT_MARGIN_AREA][0].face_id =
+               default_face->id;
+             it->glyph_row->used[RIGHT_MARGIN_AREA] = 1;
+           }
+       }
 #ifdef HAVE_WINDOW_SYSTEM
       if (it->glyph_row->reversed_p)
        {
@@ -18730,6 +19217,34 @@ extend_face_to_end_of_line (struct it *it)
       it->object = make_number (0);
       it->c = it->char_to_display = ' ';
       it->len = 1;
+
+      if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+         && (it->glyph_row->used[LEFT_MARGIN_AREA]
+             < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+         && !it->glyph_row->mode_line_p
+         && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+       {
+         struct glyph *g = it->glyph_row->glyphs[LEFT_MARGIN_AREA];
+         struct glyph *e = g + it->glyph_row->used[LEFT_MARGIN_AREA];
+
+         for (it->current_x = 0; g < e; g++)
+           it->current_x += g->pixel_width;
+
+         it->area = LEFT_MARGIN_AREA;
+         it->face_id = default_face->id;
+         while (it->glyph_row->used[LEFT_MARGIN_AREA]
+                < WINDOW_LEFT_MARGIN_WIDTH (it->w))
+           {
+             PRODUCE_GLYPHS (it);
+             /* term.c:produce_glyphs advances it->current_x only for
+                TEXT_AREA.  */
+             it->current_x += it->pixel_width;
+           }
+
+         it->current_x = saved_x;
+         it->area = TEXT_AREA;
+       }
+
       /* The last row's blank glyphs should get the default face, to
         avoid painting the rest of the window with the region face,
         if the region ends at ZV.  */
@@ -18737,12 +19252,35 @@ extend_face_to_end_of_line (struct it *it)
        it->face_id = default_face->id;
       else
        it->face_id = face->id;
-
       PRODUCE_GLYPHS (it);
 
       while (it->current_x <= it->last_visible_x)
        PRODUCE_GLYPHS (it);
 
+      if (WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0
+         && (it->glyph_row->used[RIGHT_MARGIN_AREA]
+             < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+         && !it->glyph_row->mode_line_p
+         && default_face->background != FRAME_BACKGROUND_PIXEL (f))
+       {
+         struct glyph *g = it->glyph_row->glyphs[RIGHT_MARGIN_AREA];
+         struct glyph *e = g + it->glyph_row->used[RIGHT_MARGIN_AREA];
+
+         for ( ; g < e; g++)
+           it->current_x += g->pixel_width;
+
+         it->area = RIGHT_MARGIN_AREA;
+         it->face_id = default_face->id;
+         while (it->glyph_row->used[RIGHT_MARGIN_AREA]
+                < WINDOW_RIGHT_MARGIN_WIDTH (it->w))
+           {
+             PRODUCE_GLYPHS (it);
+             it->current_x += it->pixel_width;
+           }
+
+         it->area = TEXT_AREA;
+       }
+
       /* Don't count these blanks really.  It would let us insert a left
         truncation glyph below and make us set the cursor on them, maybe.  */
       it->current_x = saved_x;
@@ -19595,6 +20133,9 @@ display_line (struct it *it)
                        }
                      else if (it->bidi_p)
                        RECORD_MAX_MIN_POS (it);
+                     if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+                         || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+                       extend_face_to_end_of_line (it);
                    }
                  else if (CHAR_GLYPH_PADDING_P (*glyph)
                           && !FRAME_WINDOW_P (it->f))
@@ -19623,6 +20164,9 @@ display_line (struct it *it)
                      it->max_descent = descent;
                      it->max_phys_ascent = phys_ascent;
                      it->max_phys_descent = phys_descent;
+                     if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+                         || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+                       extend_face_to_end_of_line (it);
                    }
                  else if (wrap_row_used > 0)
                    {
@@ -19667,6 +20211,9 @@ display_line (struct it *it)
                      row->continued_p = 1;
                      glyph->pixel_width = it->last_visible_x - x;
                      it->starts_in_middle_of_char_p = 1;
+                     if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
+                         || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)
+                       extend_face_to_end_of_line (it);
                    }
                  else
                    {
@@ -19789,7 +20336,12 @@ display_line (struct it *it)
       /* If we truncate lines, we are done when the last displayed
         glyphs reach past the right margin of the window.  */
       if (it->line_wrap == TRUNCATE
-         && (FRAME_WINDOW_P (it->f) && WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+         && ((FRAME_WINDOW_P (it->f)
+              /* Images are preprocessed in produce_image_glyph such
+                 that they are cropped at the right edge of the
+                 window, so an image glyph will always end exactly at
+                 last_visible_x, even if there's no right fringe.  */
+              && (WINDOW_RIGHT_FRINGE_WIDTH (it->w) || it->what == IT_IMAGE))
              ? (it->current_x >= it->last_visible_x)
              : (it->current_x > it->last_visible_x)))
        {
@@ -19822,19 +20374,26 @@ display_line (struct it *it)
                  i = row->used[TEXT_AREA] - (i + 1);
                }
 
-             it->current_x = x_before;
-             if (!FRAME_WINDOW_P (it->f))
+             /* produce_special_glyphs overwrites the last glyph, so
+                we don't want that if we want to keep that last
+                glyph, which means it's an image.  */
+             if (it->current_x > it->last_visible_x)
                {
-                 for (n = row->used[TEXT_AREA]; i < n; ++i)
+                 it->current_x = x_before;
+                 if (!FRAME_WINDOW_P (it->f))
+                   {
+                     for (n = row->used[TEXT_AREA]; i < n; ++i)
+                       {
+                         row->used[TEXT_AREA] = i;
+                         produce_special_glyphs (it, IT_TRUNCATION);
+                       }
+                   }
+                 else
                    {
                      row->used[TEXT_AREA] = i;
                      produce_special_glyphs (it, IT_TRUNCATION);
                    }
-               }
-             else
-               {
-                 row->used[TEXT_AREA] = i;
-                 produce_special_glyphs (it, IT_TRUNCATION);
+                 it->hpos = hpos_before;
                }
            }
          else if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
@@ -19853,13 +20412,13 @@ display_line (struct it *it)
                  goto at_end_of_line;
                }
              it->current_x = x_before;
+             it->hpos = hpos_before;
            }
 
          row->truncated_on_right_p = 1;
          it->continuation_lines_width = 0;
          reseat_at_next_visible_line_start (it, 0);
          row->ends_at_zv_p = FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n';
-         it->hpos = hpos_before;
          break;
        }
     }
@@ -19873,9 +20432,12 @@ display_line (struct it *it)
       && IT_CHARPOS (*it) != CHARPOS (row->start.pos))
     {
       if (!FRAME_WINDOW_P (it->f)
-         || (row->reversed_p
-             ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
-             : WINDOW_LEFT_FRINGE_WIDTH (it->w)) == 0)
+         || (((row->reversed_p
+               ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+               : WINDOW_LEFT_FRINGE_WIDTH (it->w)) == 0)
+             /* Don't let insert_left_trunc_glyphs overwrite the
+                first glyph of the row if it is an image.  */
+             && row->glyphs[TEXT_AREA]->type != IMAGE_GLYPH))
        insert_left_trunc_glyphs (it);
       row->truncated_on_left_p = 1;
     }
@@ -20078,6 +20640,7 @@ See also `bidi-paragraph-direction'.  */)
       itb.string.s = NULL;
       itb.string.lstring = Qnil;
       itb.string.bufpos = 0;
+      itb.string.from_disp_str = 0;
       itb.string.unibyte = 0;
       /* We have no window to use here for ignoring window-specific
         overlays.  Using NULL for window pointer will cause
@@ -20139,6 +20702,10 @@ Value is the new character position of point.  */)
       && !b->clip_changed
       && !b->prevent_redisplay_optimizations_p
       && !window_outdated (w)
+      /* We rely below on the cursor coordinates to be up to date, but
+        we cannot trust them if some command moved point since the
+        last complete redisplay.  */
+      && w->last_point == BUF_PT (b)
       && w->cursor.vpos >= 0
       && w->cursor.vpos < w->current_matrix->nrows
       && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
@@ -20322,11 +20889,26 @@ Value is the new character position of point.  */)
         of this or previous line to make sure we are before point in
         the logical order (since the move_it_* functions can only
         move forward).  */
+    reseat:
       reseat_at_previous_visible_line_start (&it);
       it.current_x = it.hpos = it.current_y = it.vpos = 0;
       if (IT_CHARPOS (it) != PT)
-       move_it_to (&it, overshoot_expected ? PT - 1 : PT,
-                   -1, -1, -1, MOVE_TO_POS);
+       {
+         move_it_to (&it, overshoot_expected ? PT - 1 : PT,
+                     -1, -1, -1, MOVE_TO_POS);
+         /* If we missed point because the character there is
+            displayed out of a display vector that has more than one
+            glyph, retry expecting overshoot.  */
+         if (it.method == GET_FROM_DISPLAY_VECTOR
+             && it.current.dpvec_index > 0
+             && !overshoot_expected)
+           {
+             overshoot_expected = true;
+             goto reseat;
+           }
+         else if (IT_CHARPOS (it) != PT && !overshoot_expected)
+           move_it_in_display_line (&it, PT, -1, MOVE_TO_POS);
+       }
       pt_x = it.current_x;
       pt_vpos = it.vpos;
       if (dir > 0 || overshoot_expected)
@@ -20355,11 +20937,16 @@ Value is the new character position of point.  */)
       else if (pixel_width <= 0)
        pixel_width = 1;
 
-      /* If there's a display string at point, we are actually at the
-        glyph to the left of point, so we need to correct the X
-        coordinate.  */
+      /* If there's a display string (or something similar) at point,
+        we are actually at the glyph to the left of point, so we need
+        to correct the X coordinate.  */
       if (overshoot_expected)
-       pt_x += pixel_width;
+       {
+         if (it.bidi_p)
+           pt_x += pixel_width * it.bidi_it.scan_dir;
+         else
+           pt_x += pixel_width;
+       }
 
       /* Compute target X coordinate, either to the left or to the
         right of point.  On TTY frames, all characters have the same
@@ -20391,6 +20978,30 @@ Value is the new character position of point.  */)
              move_it_by_lines (&it, -1);
              target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f);
              target_is_eol_p = true;
+             /* Under word-wrap, we don't know the x coordinate of
+                the last character displayed on the previous line,
+                which immediately precedes the wrap point.  To find
+                out its x coordinate, we try moving to the right
+                margin of the window, which will stop at the wrap
+                point, and then reset target_x to point at the
+                character that precedes the wrap point.  This is not
+                needed on GUI frames, because (see below) there we
+                move from the left margin one grapheme cluster at a
+                time, and stop when we hit the wrap point.  */
+             if (!FRAME_WINDOW_P (it.f) && it.line_wrap == WORD_WRAP)
+               {
+                 void *it_data = NULL;
+                 struct it it2;
+
+                 SAVE_IT (it2, it, it_data);
+                 move_it_in_display_line_to (&it, ZV, target_x,
+                                             MOVE_TO_POS | MOVE_TO_X);
+                 /* If we arrived at target_x, that _is_ the last
+                    character on the previous line.  */
+                 if (it.current_x != target_x)
+                   target_x = it.current_x - 1;
+                 RESTORE_IT (&it, &it2, it_data);
+               }
            }
        }
       else
@@ -20415,15 +21026,42 @@ Value is the new character position of point.  */)
         character at point.  */
       if (FRAME_WINDOW_P (it.f) && dir < 0)
        {
-         struct text_pos new_pos = it.current.pos;
+         struct text_pos new_pos;
          enum move_it_result rc = MOVE_X_REACHED;
 
+         if (it.current_x == 0)
+           get_next_display_element (&it);
+         if (it.what == IT_COMPOSITION)
+           {
+             new_pos.charpos = it.cmp_it.charpos;
+             new_pos.bytepos = -1;
+           }
+         else
+           new_pos = it.current.pos;
+
          while (it.current_x + it.pixel_width <= target_x
-                && rc == MOVE_X_REACHED)
+                && (rc == MOVE_X_REACHED
+                    /* Under word-wrap, move_it_in_display_line_to
+                       stops at correct coordinates, but sometimes
+                       returns MOVE_POS_MATCH_OR_ZV.  */
+                    || (it.line_wrap == WORD_WRAP
+                        && rc == MOVE_POS_MATCH_OR_ZV)))
            {
              int new_x = it.current_x + it.pixel_width;
 
-             new_pos = it.current.pos;
+             /* For composed characters, we want the position of the
+                first character in the grapheme cluster (usually, the
+                composition's base character), whereas it.current
+                might give us the position of the _last_ one, e.g. if
+                the composition is rendered in reverse due to bidi
+                reordering.  */
+             if (it.what == IT_COMPOSITION)
+               {
+                 new_pos.charpos = it.cmp_it.charpos;
+                 new_pos.bytepos = -1;
+               }
+             else
+               new_pos = it.current.pos;
              if (new_x == it.current_x)
                new_x++;
              rc = move_it_in_display_line_to (&it, ZV, new_x,
@@ -20431,21 +21069,10 @@ Value is the new character position of point.  */)
              if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p)
                break;
            }
-         /* If we ended up on a composed character inside
-            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
-            character position of the character that follows (in the
-            logical order) the one where the above loop stopped.  That
-            character will appear on display to the left of point.  */
-         if (it.bidi_p
-             && it.bidi_it.scan_dir == -1
-             && new_pos.charpos - IT_CHARPOS (it) > 1)
-           {
-             new_pos.charpos = IT_CHARPOS (it) + 1;
-             new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
-           }
+         /* The previous position we saw in the loop is the one we
+            want.  */
+         if (new_pos.bytepos == -1)
+           new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
          it.current.pos = new_pos;
        }
       else
@@ -20537,7 +21164,7 @@ display_menu_bar (struct window *w)
   eassert (!FRAME_WINDOW_P (f));
   init_iterator (&it, w, -1, -1, f->desired_matrix->rows, MENU_FACE_ID);
   it.first_visible_x = 0;
-  it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+  it.last_visible_x = FRAME_PIXEL_WIDTH (f);
 #elif defined (HAVE_X_WINDOWS) /* X without toolkit.  */
   if (FRAME_WINDOW_P (f))
     {
@@ -20548,7 +21175,7 @@ display_menu_bar (struct window *w)
       init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
                     MENU_FACE_ID);
       it.first_visible_x = 0;
-      it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
+      it.last_visible_x = FRAME_PIXEL_WIDTH (f);
     }
   else
 #endif /* not USE_X_TOOLKIT and not USE_GTK */
@@ -20571,7 +21198,7 @@ display_menu_bar (struct window *w)
     {
       struct glyph_row *row = it.glyph_row + i;
       clear_glyph_row (row);
-      row->enabled_p = 1;
+      row->enabled_p = true;
       row->full_width_p = 1;
     }
 
@@ -20603,7 +21230,6 @@ display_menu_bar (struct window *w)
   compute_line_metrics (&it);
 }
 
-#ifdef HAVE_MENUS
 /* Deep copy of a glyph row, including the glyphs.  */
 static void
 deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from)
@@ -20682,7 +21308,7 @@ display_tty_menu_item (const char *item_text, int width, int face_id,
   row->full_width_p = 1;
   saved_reversed = row->reversed_p;
   row->reversed_p = 0;
-  row->enabled_p = 1;
+  row->enabled_p = true;
 
   /* Arrange for the menu item glyphs to start at (X,Y) and have the
      desired face.  */
@@ -20725,7 +21351,6 @@ display_tty_menu_item (const char *item_text, int width, int face_id,
   row->full_width_p = saved_width;
   row->reversed_p = saved_reversed;
 }
-#endif /* HAVE_MENUS */
 \f
 /***********************************************************************
                              Mode Line
@@ -20737,7 +21362,7 @@ display_tty_menu_item (const char *item_text, int width, int face_id,
    the number of windows whose mode lines were redisplayed.  */
 
 static int
-redisplay_mode_lines (Lisp_Object window, int force)
+redisplay_mode_lines (Lisp_Object window, bool force)
 {
   int nwindows = 0;
 
@@ -20771,10 +21396,7 @@ redisplay_mode_lines (Lisp_Object window, int force)
          /* Display mode lines.  */
          clear_glyph_matrix (w->desired_matrix);
          if (display_mode_lines (w))
-           {
-             ++nwindows;
-             w->must_be_updated_p = 1;
-           }
+           ++nwindows;
 
          /* Restore old settings.  */
          set_buffer_internal_1 (old);
@@ -20830,6 +21452,8 @@ display_mode_lines (struct window *w)
   XFRAME (new_frame)->selected_window = old_frame_selected_window;
   selected_frame = old_selected_frame;
   selected_window = old_selected_window;
+  if (n > 0)
+    w->must_be_updated_p = true;
   return n;
 }
 
@@ -20845,12 +21469,12 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
 {
   struct it it;
   struct face *face;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
   /* Don't extend on a previously drawn mode-line.
      This may happen if called from pos_visible_p.  */
-  it.glyph_row->enabled_p = 0;
+  it.glyph_row->enabled_p = false;
   prepare_desired_row (it.glyph_row);
 
   it.glyph_row->mode_line_p = 1;
@@ -20873,7 +21497,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
   pop_kboard ();
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Fill up with spaces.  */
   display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
@@ -21272,7 +21896,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
            if (CONSP (XCDR (elt)))
              {
                Lisp_Object spec;
-               spec = safe_eval (XCAR (XCDR (elt)));
+               spec = safe__eval (true, XCAR (XCDR (elt)));
                n += display_mode_element (it, depth, field_width - n,
                                           precision - n, spec, props,
                                           risky);
@@ -21525,7 +22149,7 @@ are the selected window and the WINDOW's buffer).  */)
   struct buffer *old_buffer = NULL;
   int face_id;
   int no_props = INTEGERP (face);
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object str;
   int string_start = 0;
 
@@ -21538,8 +22162,10 @@ are the selected window and the WINDOW's buffer).  */)
 
   /* Make formatting the modeline a non-op when noninteractive, otherwise
      there will be problems later caused by a partially initialized frame.  */
-  if (NILP (format) || noninteractive)
+  if (NILP (format) || noninteractive) {
+    dynwind_end ();
     return empty_unibyte_string;
+  }
 
   if (no_props)
     face = Qnil;
@@ -21600,7 +22226,7 @@ are the selected window and the WINDOW's buffer).  */)
                        empty_unibyte_string);
     }
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return str;
 }
 
@@ -22089,7 +22715,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        return decode_mode_spec_buf;
     no_value:
         {
-         charp = decode_mode_spec_buf;
+         char *p = decode_mode_spec_buf;
          int pad = width - 2;
          while (pad-- > 0)
            *p++ = ' ';
@@ -22185,10 +22811,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case '@':
       {
-       ptrdiff_t count = inhibit_garbage_collection ();
        Lisp_Object val = call1 (intern ("file-remote-p"),
                                 BVAR (current_buffer, directory));
-       unbind_to (count, Qnil);
 
        if (NILP (val))
          return "-";
@@ -22837,7 +23461,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
            return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
        }
 
-      prop = buffer_local_value_1 (prop, it->w->contents);
+      prop = buffer_local_value (prop, it->w->contents);
       if (EQ (prop, Qunbound))
        prop = Qnil;
     }
@@ -22889,7 +23513,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
              return OK_PIXELS (pixels);
            }
 
-         car = buffer_local_value_1 (car, it->w->contents);
+         car = buffer_local_value (car, it->w->contents);
          if (EQ (car, Qunbound))
            car = Qnil;
        }
@@ -23066,7 +23690,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id,
 #endif
     {
       eassert (face != NULL);
-      PREPARE_FACE_FOR_DISPLAY (f, face);
+      prepare_face_for_display (f, face);
     }
 
   return face;
@@ -23089,7 +23713,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
 
   /* Make sure X resources of the face are allocated.  */
   eassert (face != NULL);
-  PREPARE_FACE_FOR_DISPLAY (f, face);
+  prepare_face_for_display (f, face);
 
   if (two_byte_p)
     *two_byte_p = 0;
@@ -23406,7 +24030,7 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end)
   s->ybase += voffset;
 
   /* The case that face->gc == 0 is handled when drawing the glyph
-     string by calling PREPARE_FACE_FOR_DISPLAY.  */
+     string by calling prepare_face_for_display.  */
   eassert (s->face);
   return glyph - s->row->glyphs[s->area];
 }
@@ -23597,7 +24221,6 @@ set_glyph_string_background_width (struct glyph_string *s, int start, int last_x
      the drawing area, set S->extends_to_end_of_line_p.  */
 
   if (start == s->row->used[s->area]
-      && s->area == TEXT_AREA
       && ((s->row->fill_line_p
           && (s->hl == DRAW_NORMAL_TEXT
               || s->hl == DRAW_IMAGE_RAISED
@@ -23925,7 +24548,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
       /* X is relative to the left edge of W, without scroll bars
         or fringes.  */
       area_left = WINDOW_LEFT_EDGE_X (w);
-      last_x = WINDOW_LEFT_EDGE_X (w) + WINDOW_TOTAL_WIDTH (w);
+      last_x = (WINDOW_LEFT_EDGE_X (w) + WINDOW_PIXEL_WIDTH (w)
+               - (row->mode_line_p ? WINDOW_RIGHT_DIVIDER_WIDTH (w) : 0));
     }
   else
     {
@@ -24004,13 +24628,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
+         if (hl != overlap_hl)
+           clip_head = head;
          j = i;
          BUILD_GLYPH_STRINGS (j, start, h, t,
                               overlap_hl, dummy_x, last_x);
          start = i;
          compute_overhangs_and_x (t, head->x, 1);
          prepend_glyph_string_lists (&head, &tail, h, t);
-         clip_head = head;
+         if (clip_head == NULL)
+           clip_head = head;
        }
 
       /* Prepend glyph strings for glyphs in front of the first glyph
@@ -24031,7 +24658,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
-         clip_head = head;
+         if (hl == overlap_hl || clip_head == NULL)
+           clip_head = head;
          BUILD_GLYPH_STRINGS (i, start, h, t,
                               overlap_hl, dummy_x, last_x);
          for (s = h; s; s = s->next)
@@ -24055,13 +24683,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
+         if (hl != overlap_hl)
+           clip_tail = tail;
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
          /* Because BUILD_GLYPH_STRINGS updates the first argument,
             we don't have `end = i;' here.  */
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
-         clip_tail = tail;
+         if (clip_tail == NULL)
+           clip_tail = tail;
        }
 
       /* Append glyph strings for glyphs following the last glyph
@@ -24079,7 +24710,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
-         clip_tail = tail;
+         if (hl == overlap_hl || clip_tail == NULL)
+           clip_tail = tail;
          i++;                  /* We must include the Ith glyph.  */
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
@@ -24347,7 +24979,7 @@ produce_image_glyph (struct it *it)
   face = FACE_FROM_ID (it->f, it->face_id);
   eassert (face);
   /* Make sure X resources of the face is loaded.  */
-  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+  prepare_face_for_display (it->f, face);
 
   if (it->image_id < 0)
     {
@@ -24625,7 +25257,7 @@ produce_stretch_glyph (struct it *it)
     {
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
-      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+      prepare_face_for_display (it->f, face);
     }
 #endif
 
@@ -25089,7 +25721,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
 
       face = FACE_FROM_ID (it->f, face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
-      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+      prepare_face_for_display (it->f, face);
 
       if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
        {
@@ -25105,7 +25737,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
          sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
          str = buf;
        }
-      for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++)
+      for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++)
        code[len] = font->driver->encode_char (font, str[len]);
       upper_len = (len + 1) / 2;
       font->driver->text_extents (font, code, upper_len,
@@ -25963,7 +26595,8 @@ x_clear_end_of_line (struct window *w, struct glyph_row *updated_row,
   f = XFRAME (w->frame);
 
   if (updated_row->full_width_p)
-    max_x = WINDOW_TOTAL_WIDTH (w);
+    max_x = (WINDOW_PIXEL_WIDTH (w)
+            - (updated_row->mode_line_p ? WINDOW_RIGHT_DIVIDER_WIDTH (w) : 0));
   else
     max_x = window_box_width (w, updated_area);
   max_y = window_text_bottom_y (w);
@@ -26429,9 +27062,6 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
 
 /* Erase the image of a cursor of window W from the screen.  */
 
-#ifndef HAVE_NTGUI
-static
-#endif
 void
 erase_phys_cursor (struct window *w)
 {
@@ -26740,7 +27370,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
   if (/* If window is in the process of being destroyed, don't bother
         to do anything.  */
       w->current_matrix != NULL
-      /* Don't update mouse highlight if hidden */
+      /* Don't update mouse highlight if hidden */
       && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
       /* Recognize when we are called to operate on rows that don't exist
         anymore.  This can happen when a window is split.  */
@@ -26880,13 +27510,16 @@ clear_mouse_face (Mouse_HLInfo *hlinfo)
       cleared = 1;
     }
 
-  reset_mouse_highlight (hlinfo);
+  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;
   return cleared;
 }
 
-/* Return non-zero if the coordinates HPOS and VPOS on windows W are
+/* Return true if the coordinates HPOS and VPOS on windows W are
    within the mouse face on that window.  */
-static int
+static bool
 coords_in_mouse_face_p (struct window *w, int hpos, int vpos)
 {
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
@@ -26894,48 +27527,48 @@ coords_in_mouse_face_p (struct window *w, int hpos, int vpos)
   /* Quickly resolve the easy cases.  */
   if (!(WINDOWP (hlinfo->mouse_face_window)
        && XWINDOW (hlinfo->mouse_face_window) == w))
-    return 0;
+    return false;
   if (vpos < hlinfo->mouse_face_beg_row
       || vpos > hlinfo->mouse_face_end_row)
-    return 0;
+    return false;
   if (vpos > hlinfo->mouse_face_beg_row
       && vpos < hlinfo->mouse_face_end_row)
-    return 1;
+    return true;
 
   if (!MATRIX_ROW (w->current_matrix, vpos)->reversed_p)
     {
       if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
        {
          if (hlinfo->mouse_face_beg_col <= hpos && hpos < hlinfo->mouse_face_end_col)
-           return 1;
+           return true;
        }
       else if ((vpos == hlinfo->mouse_face_beg_row
                && hpos >= hlinfo->mouse_face_beg_col)
               || (vpos == hlinfo->mouse_face_end_row
                   && hpos < hlinfo->mouse_face_end_col))
-       return 1;
+       return true;
     }
   else
     {
        if (hlinfo->mouse_face_beg_row == hlinfo->mouse_face_end_row)
        {
          if (hlinfo->mouse_face_end_col < hpos && hpos <= hlinfo->mouse_face_beg_col)
-           return 1;
+           return true;
        }
       else if ((vpos == hlinfo->mouse_face_beg_row
                && hpos <= hlinfo->mouse_face_beg_col)
               || (vpos == hlinfo->mouse_face_end_row
                   && hpos > hlinfo->mouse_face_end_col))
-       return 1;
+       return true;
     }
-  return 0;
+  return false;
 }
 
 
 /* EXPORT:
-   Non-zero if physical cursor of window W is within mouse face.  */
+   True if physical cursor of window W is within mouse face.  */
 
-int
+bool
 cursor_in_mouse_face_p (struct window *w)
 {
   int hpos = w->phys_cursor.hpos;
@@ -27804,6 +28437,8 @@ define_frame_cursor1 (struct frame *f, Cursor cursor, Lisp_Object pointer)
        cursor = FRAME_X_OUTPUT (f)->text_cursor;
       else if (EQ (pointer, intern ("hdrag")))
        cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+      else if (EQ (pointer, intern ("nhdrag")))
+       cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
 #ifdef HAVE_X_WINDOWS
       else if (EQ (pointer, intern ("vdrag")))
        cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
@@ -27952,8 +28587,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
          else if (area == ON_MODE_LINE)
            {
              Lisp_Object default_help
-               = buffer_local_value_1 (Qmode_line_default_help_echo,
-                                       w->contents);
+               = buffer_local_value (Qmode_line_default_help_echo,
+                                     w->contents);
 
              if (STRINGP (default_help))
                {
@@ -27969,6 +28604,10 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
       /* Change the mouse pointer according to what is under it.  */
       if (FRAME_WINDOW_P (f))
        {
+         bool draggable = (! WINDOW_BOTTOMMOST_P (w)
+                           || minibuf_level
+                           || NILP (Vresize_mini_windows));
+
          dpyinfo = FRAME_DISPLAY_INFO (f);
          if (STRINGP (string))
            {
@@ -27985,11 +28624,11 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
                  map = Fget_text_property (pos, Qlocal_map, string);
                  if (!KEYMAPP (map))
                    map = Fget_text_property (pos, Qkeymap, string);
-                 if (!KEYMAPP (map))
+                 if (!KEYMAPP (map) && draggable)
                    cursor = dpyinfo->vertical_scroll_bar_cursor;
                }
            }
-         else
+         else if (draggable)
            /* Default mode-line pointer.  */
            cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
        }
@@ -28208,7 +28847,17 @@ note_mouse_highlight (struct frame *f, int x, int y)
       || part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
     {
       note_mode_line_or_margin_highlight (window, x, y, part);
-      return;
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
+       {
+         cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+         /* Show non-text cursor (Bug#16647).  */
+         goto set_cursor;
+       }
+      else
+#endif
+       return;
     }
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -28217,6 +28866,21 @@ note_mouse_highlight (struct frame *f, int x, int y)
       cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
       help_echo_string = build_string ("drag-mouse-1: resize");
     }
+  else if (part == ON_RIGHT_DIVIDER)
+    {
+      cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+      help_echo_string = build_string ("drag-mouse-1: resize");
+    }
+  else if (part == ON_BOTTOM_DIVIDER)
+    if (! WINDOW_BOTTOMMOST_P (w)
+       || minibuf_level
+       || NILP (Vresize_mini_windows))
+      {
+       cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
+       help_echo_string = build_string ("drag-mouse-1: resize");
+      }
+    else
+      cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
   else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
           || part == ON_SCROLL_BAR)
     cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
@@ -28857,7 +29521,7 @@ x_draw_vertical_border (struct window *w)
      do it for frames with vertical scroll bars because either the
      right scroll bar of a window, or the left scroll bar of its
      neighbor will suffice as a border.  */
-  if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame)))
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f) || FRAME_RIGHT_DIVIDER_WIDTH (f))
     return;
 
   /* Note: It is necessary to redraw both the left and the right
@@ -28876,6 +29540,7 @@ x_draw_vertical_border (struct window *w)
 
       FRAME_RIF (f)->draw_vertical_window_border (w, x1, y0, y1);
     }
+
   if (!WINDOW_LEFTMOST_P (w)
       && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
     {
@@ -28892,6 +29557,45 @@ x_draw_vertical_border (struct window *w)
 }
 
 
+/* Draw window dividers for window W.  */
+
+void
+x_draw_right_divider (struct window *w)
+{
+  struct frame *f = WINDOW_XFRAME (w);
+
+  if (w->mini || w->pseudo_window_p)
+    return;
+  else if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+    {
+      int x0 = WINDOW_RIGHT_EDGE_X (w) - WINDOW_RIGHT_DIVIDER_WIDTH (w);
+      int x1 = WINDOW_RIGHT_EDGE_X (w);
+      int y0 = WINDOW_TOP_EDGE_Y (w);
+      /* The bottom divider prevails.  */
+      int y1 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+
+      FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+    }
+}
+
+static void
+x_draw_bottom_divider (struct window *w)
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+
+  if (w->mini || w->pseudo_window_p)
+    return;
+  else if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+    {
+      int x0 = WINDOW_LEFT_EDGE_X (w);
+      int x1 = WINDOW_RIGHT_EDGE_X (w);
+      int y0 = WINDOW_BOTTOM_EDGE_Y (w) - WINDOW_BOTTOM_DIVIDER_WIDTH (w);
+      int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+
+      FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+    }
+}
+
 /* Redraw the part of window W intersection rectangle FR.  Pixel
    coordinates in FR are frame-relative.  Call this function with
    input blocked.  Value is non-zero if the exposure overwrites
@@ -28923,8 +29627,8 @@ expose_window (struct window *w, XRectangle *fr)
   /* Frame-relative pixel rectangle of W.  */
   wr.x = WINDOW_LEFT_EDGE_X (w);
   wr.y = WINDOW_TOP_EDGE_Y (w);
-  wr.width = WINDOW_TOTAL_WIDTH (w);
-  wr.height = WINDOW_TOTAL_HEIGHT (w);
+  wr.width = WINDOW_PIXEL_WIDTH (w);
+  wr.height = WINDOW_PIXEL_HEIGHT (w);
 
   if (x_intersect_rectangles (fr, &wr, &r))
     {
@@ -29020,7 +29724,13 @@ expose_window (struct window *w, XRectangle *fr)
                             fr);
 
          /* Draw border between windows.  */
-         x_draw_vertical_border (w);
+         if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
+           x_draw_right_divider (w);
+         else
+           x_draw_vertical_border (w);
+
+         if (WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+           x_draw_bottom_divider (w);
 
          /* Turn the cursor on again.  */
          if (cursor_cleared_p
@@ -29213,6 +29923,8 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result)
 void
 syms_of_xdisp (void)
 {
+#include "xdisp.x"
+
   Vwith_echo_area_save_vector = Qnil;
   staticpro (&Vwith_echo_area_save_vector);
 
@@ -29229,24 +29941,6 @@ syms_of_xdisp (void)
   message_dolog_marker3 = Fmake_marker ();
   staticpro (&message_dolog_marker3);
 
-#ifdef GLYPH_DEBUG
-  defsubr (&Sdump_frame_glyph_matrix);
-  defsubr (&Sdump_glyph_matrix);
-  defsubr (&Sdump_glyph_row);
-  defsubr (&Sdump_tool_bar_row);
-  defsubr (&Strace_redisplay);
-  defsubr (&Strace_to_stderr);
-#endif
-#ifdef HAVE_WINDOW_SYSTEM
-  defsubr (&Stool_bar_lines_needed);
-  defsubr (&Slookup_image_map);
-#endif
-  defsubr (&Sline_pixel_height);
-  defsubr (&Sformat_mode_line);
-  defsubr (&Sinvisible_p);
-  defsubr (&Scurrent_bidi_paragraph_direction);
-  defsubr (&Smove_point_visually);
-
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
   DEFSYM (Qoverriding_local_map, "overriding-local-map");
@@ -29706,8 +30400,8 @@ Bind this around calls to `message' to let it take effect.  */);
   DEFVAR_LISP ("menu-bar-update-hook",  Vmenu_bar_update_hook,
     doc: /* Normal hook run to update the menu bar definitions.
 Redisplay runs this hook before it redisplays the menu bar.
-This is used to update submenus such as Buffers,
-whose contents depend on various data.  */);
+This is used to update menus such as Buffers, whose contents depend on
+various data.  */);
   Vmenu_bar_update_hook = Qnil;
 
   DEFVAR_LISP ("menu-updating-frame", Vmenu_updating_frame,
@@ -29872,12 +30566,18 @@ init_xdisp (void)
       echo_area_window = minibuf_window;
 
       r->top_line = FRAME_TOP_MARGIN (f);
-      r->total_lines = FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f);
+      r->pixel_top = r->top_line * FRAME_LINE_HEIGHT (f);
       r->total_cols = FRAME_COLS (f);
+      r->pixel_width = r->total_cols * FRAME_COLUMN_WIDTH (f);
+      r->total_lines = FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f);
+      r->pixel_height = r->total_lines * FRAME_LINE_HEIGHT (f);
 
       m->top_line = FRAME_LINES (f) - 1;
-      m->total_lines = 1;
+      m->pixel_top = m->top_line * FRAME_LINE_HEIGHT (f);
       m->total_cols = FRAME_COLS (f);
+      m->pixel_width = m->total_cols * FRAME_COLUMN_WIDTH (f);
+      m->total_lines = 1;
+      m->pixel_height = m->total_lines * FRAME_LINE_HEIGHT (f);
 
       scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
       scratch_glyph_row.glyphs[TEXT_AREA + 1]
@@ -29892,7 +30592,7 @@ init_xdisp (void)
     /* Allocate the buffer for frame titles.
        Also used for `format-mode-line'.  */
     int size = 100;
-    mode_line_noprop_buf = xmalloc (size);
+    mode_line_noprop_buf = xmalloc_atomic (size);
     mode_line_noprop_buf_end = mode_line_noprop_buf + size;
     mode_line_noprop_ptr = mode_line_noprop_buf;
     mode_line_target = MODE_LINE_DISPLAY;