Support resizing frames and windows pixelwise.
[bpt/emacs.git] / src / xdisp.c
index 22ada20..8e2c18f 100644 (file)
@@ -502,12 +502,20 @@ static Lisp_Object Vmessage_stack;
 
 static bool message_enable_multibyte;
 
-/* Nonzero if we should redraw the mode lines on the next redisplay.  */
+/* Nonzero if we should redraw the mode lines on the next redisplay.
+   If it has value REDISPLAY_SOME, then only redisplay the mode lines where
+   the `redisplay' bit has been set.  Otherwise, redisplay all mode lines
+   (the number used is then only used to track down the cause for this
+   full-redisplay).  */
 
 int update_mode_lines;
 
-/* Nonzero if window sizes or contents have changed since last
-   redisplay that finished.  */
+/* Nonzero if window sizes or contents other than selected-window have changed
+   since last redisplay that finished.
+   If it has value REDISPLAY_SOME, then only redisplay the windows where
+   the `redisplay' bit has been set.  Otherwise, redisplay all windows
+   (the number used is then only used to track down the cause for this
+   full-redisplay).  */
 
 int windows_or_buffers_changed;
 
@@ -562,7 +570,7 @@ static struct glyph scratch_glyphs[MAX_SCRATCH_GLYPHS];
 
 /* Ascent and height of the last line processed by move_it_to.  */
 
-static int last_height;
+static int last_max_ascent, last_height;
 
 /* Non-zero if there's a help-echo in the echo area.  */
 
@@ -599,6 +607,54 @@ bool help_echo_showing_p;
     CACHE = NULL;                              \
   } while (0)
 
+/* Functions to mark elements as needing redisplay.  */
+enum { REDISPLAY_SOME = 2};    /* Arbitrary choice.  */
+
+void
+redisplay_other_windows (void)
+{
+  if (!windows_or_buffers_changed)
+    windows_or_buffers_changed = REDISPLAY_SOME;
+}
+
+void
+wset_redisplay (struct window *w)
+{
+  redisplay_other_windows ();
+  w->redisplay = true;
+}
+
+void
+fset_redisplay (struct frame *f)
+{
+  redisplay_other_windows ();
+  f->redisplay = true;
+}
+
+void
+bset_redisplay (struct buffer *b)
+{
+  int count = buffer_window_count (b);
+  if (count > 0)
+    {
+      /* ... it's visible in other window than selected,  */
+      if (count > 1 || b != XBUFFER (XWINDOW (selected_window)->contents))
+       redisplay_other_windows ();
+      /* Even if we don't set windows_or_buffers_changed, do set `redisplay'
+        so that if we later set windows_or_buffers_changed, this buffer will
+        not be omitted.  */
+      b->text->redisplay = true;
+    }
+}
+
+void
+bset_update_mode_line (struct buffer *b)
+{
+  if (!update_mode_lines)
+    update_mode_lines = REDISPLAY_SOME;
+  b->text->redisplay = true;
+}
+
 #ifdef GLYPH_DEBUG
 
 /* Non-zero means print traces of redisplay if compiled with
@@ -737,7 +793,7 @@ ptrdiff_t help_echo_pos;
 
 Lisp_Object previous_help_echo_string;
 
-/* Platform-independent portion of hourglass implementation. */
+/* Platform-independent portion of hourglass implementation.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
 
@@ -751,7 +807,7 @@ struct atimer *hourglass_atimer;
 #endif /* HAVE_WINDOW_SYSTEM */
 
 /* Name of the face used to display glyphless characters.  */
-Lisp_Object Qglyphless_char;
+static Lisp_Object Qglyphless_char;
 
 /* Symbol for the purpose of Vglyphless_char_display.  */
 static Lisp_Object Qglyphless_char_display;
@@ -779,7 +835,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);
@@ -833,7 +889,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);
@@ -942,10 +998,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;
 }
 
@@ -956,32 +1015,23 @@ 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 pixels = w->pixel_width;
 
   if (!w->pseudo_window_p)
     {
-      cols -= WINDOW_SCROLL_BAR_COLS (w);
+      pixels -= WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+      pixels -= 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);
-       }
+       pixels -= (WINDOW_MARGINS_WIDTH (w)
+                  + WINDOW_FRINGES_WIDTH (w));
       else if (area == LEFT_MARGIN_AREA)
-       {
-         cols = max (0, w->left_margin_cols);
-         pixels = 0;
-       }
+       pixels = WINDOW_LEFT_MARGIN_WIDTH (w);
       else if (area == RIGHT_MARGIN_AREA)
-       {
-         cols = max (0, w->right_margin_cols);
-         pixels = 0;
-       }
+       pixels = WINDOW_RIGHT_MARGIN_WIDTH (w);
     }
 
-  return cols * WINDOW_FRAME_COLUMN_WIDTH (w) + pixels;
+  return pixels;
 }
 
 
@@ -992,10 +1042,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
@@ -1373,7 +1425,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)
@@ -1611,7 +1663,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;
@@ -1854,6 +1906,8 @@ 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 pixelized before converting to
+        columns/lines ?  */
       if (!noclip)
        {
          if (pix_x < 0)
@@ -1994,7 +2048,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.  */
@@ -2262,9 +2319,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);
@@ -2422,6 +2484,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
       goto store_rect;
     }
 
+ pixelwise:
   gx += WINDOW_LEFT_EDGE_X (w);
   gy += WINDOW_TOP_EDGE_Y (w);
 
@@ -2601,24 +2664,6 @@ check_window_end (struct window *w)
 
 #endif /* GLYPH_DEBUG and ENABLE_CHECKING */
 
-/* Return mark position if current buffer has the region of non-zero length,
-   or -1 otherwise.  */
-
-static ptrdiff_t
-markpos_of_region (void)
-{
-  if (!NILP (Vtransient_mark_mode)
-      && !NILP (BVAR (current_buffer, mark_active))
-      && XMARKER (BVAR (current_buffer, mark))->buffer != NULL)
-    {
-      ptrdiff_t markpos = XMARKER (BVAR (current_buffer, mark))->charpos;
-
-      if (markpos != PT)
-       return markpos;
-    }
-  return -1;
-}
-
 /***********************************************************************
                       Iterator initialization
  ***********************************************************************/
@@ -2647,7 +2692,6 @@ init_iterator (struct it *it, struct window *w,
               ptrdiff_t charpos, ptrdiff_t bytepos,
               struct glyph_row *row, enum face_id base_face_id)
 {
-  ptrdiff_t markpos;
   enum face_id remapped_base_face_id = base_face_id;
 
   /* Some precondition checks.  */
@@ -2751,28 +2795,6 @@ init_iterator (struct it *it, struct window *w,
   /* Are multibyte characters enabled in current_buffer?  */
   it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
 
-  /* If visible region is of non-zero length, set IT->region_beg_charpos
-     and IT->region_end_charpos to the start and end of a visible region
-     in window IT->w.  Set both to -1 to indicate no region.  */
-  markpos = markpos_of_region ();
-  if (markpos >= 0
-      /* Maybe highlight only in selected window.  */
-      && (/* Either show region everywhere.  */
-         highlight_nonselected_windows
-         /* Or show region in the selected window.  */
-         || w == XWINDOW (selected_window)
-         /* Or show the region if we are in the mini-buffer and W is
-            the window the mini-buffer refers to.  */
-         || (MINI_WINDOW_P (XWINDOW (selected_window))
-             && WINDOWP (minibuf_selected_window)
-             && w == XWINDOW (minibuf_selected_window))))
-    {
-      it->region_beg_charpos = min (PT, markpos);
-      it->region_end_charpos = max (PT, markpos);
-    }
-  else
-    it->region_beg_charpos = it->region_end_charpos = -1;
-
   /* Get the position at which the redisplay_end_trigger hook should
      be run, if it is to be run at all.  */
   if (MARKERP (w->redisplay_end_trigger)
@@ -2792,6 +2814,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;
@@ -2851,12 +2874,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));
 
@@ -2898,7 +2921,7 @@ init_iterator (struct it *it, struct window *w,
         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;
+       it->start_of_box_run_p = true;
     }
 
   /* If a buffer position was specified, set the iterator there,
@@ -3326,7 +3349,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;
@@ -3406,16 +3429,6 @@ compute_stop_pos (struct it *it)
       if (pos < it->stop_charpos)
        it->stop_charpos = pos;
 
-      /* If showing the region, we have to stop at the region
-        start or end because the face might change there.  */
-      if (it->region_beg_charpos > 0)
-       {
-         if (IT_CHARPOS (*it) < it->region_beg_charpos)
-           it->stop_charpos = min (it->stop_charpos, it->region_beg_charpos);
-         else if (IT_CHARPOS (*it) < it->region_end_charpos)
-           it->stop_charpos = min (it->stop_charpos, it->region_end_charpos);
-       }
-
       /* Set up variables for computing the stop position from text
          property changes.  */
       XSETBUFFER (object, current_buffer);
@@ -3698,8 +3711,8 @@ handle_fontified_prop (struct it *it)
       ptrdiff_t count = SPECPDL_INDEX ();
       Lisp_Object val;
       struct buffer *obuf = current_buffer;
-      int begv = BEGV, zv = ZV;
-      int old_clip_changed = current_buffer->clip_changed;
+      ptrdiff_t begv = BEGV, zv = ZV;
+      bool old_clip_changed = current_buffer->clip_changed;
 
       val = Vfontification_functions;
       specbind (Qfontification_functions, Qnil);
@@ -3799,8 +3812,6 @@ handle_face_prop (struct it *it)
       new_face_id
        = face_at_buffer_position (it->w,
                                   IT_CHARPOS (*it),
-                                  it->region_beg_charpos,
-                                  it->region_end_charpos,
                                   &next_stop,
                                   (IT_CHARPOS (*it)
                                    + TEXT_PROP_DISTANCE_LIMIT),
@@ -3877,8 +3888,6 @@ handle_face_prop (struct it *it)
          base_face_id
            = face_for_overlay_string (it->w,
                                       IT_CHARPOS (*it),
-                                      it->region_beg_charpos,
-                                      it->region_end_charpos,
                                       &next_stop,
                                       (IT_CHARPOS (*it)
                                        + TEXT_PROP_DISTANCE_LIMIT),
@@ -3907,8 +3916,6 @@ handle_face_prop (struct it *it)
                                             it->string,
                                             IT_STRING_CHARPOS (*it),
                                             bufpos,
-                                            it->region_beg_charpos,
-                                            it->region_end_charpos,
                                             &next_stop,
                                             base_face_id, 0);
 
@@ -4051,8 +4058,6 @@ face_before_or_after_it_pos (struct it *it, int before_p)
                                         it->string,
                                         charpos,
                                         bufpos,
-                                        it->region_beg_charpos,
-                                        it->region_end_charpos,
                                         &next_check_charpos,
                                         base_face_id, 0);
 
@@ -4142,8 +4147,6 @@ face_before_or_after_it_pos (struct it *it, int before_p)
       /* Determine face for CHARSET_ASCII, or unibyte.  */
       face_id = face_at_buffer_position (it->w,
                                         CHARPOS (pos),
-                                        it->region_beg_charpos,
-                                        it->region_end_charpos,
                                         &next_check_charpos,
                                         limit, 0, -1);
 
@@ -4211,13 +4214,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)
            {
@@ -4329,9 +4332,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);
 
@@ -4339,10 +4342,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,
@@ -4449,7 +4452,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.  */
@@ -4473,8 +4476,8 @@ setup_for_ellipsis (struct it *it, int len)
   if (it->dp && VECTORP (DISP_INVIS_VECTOR (it->dp)))
     {
       struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
-      it->dpvec = v->u.contents;
-      it->dpend = v->u.contents + v->header.size;
+      it->dpvec = v->contents;
+      it->dpend = v->contents + v->header.size;
     }
   else
     {
@@ -4494,7 +4497,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;
 }
 
 
@@ -4963,7 +4966,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
@@ -5045,7 +5048,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;
@@ -5065,7 +5068,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.  */
@@ -5431,7 +5434,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
     {
@@ -6114,7 +6117,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
        {
@@ -6441,9 +6444,6 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
                  ptrdiff_t charpos, ptrdiff_t precision, int field_width,
                  int multibyte)
 {
-  /* No region in strings.  */
-  it->region_beg_charpos = it->region_end_charpos = -1;
-
   /* No text property checks performed by default, but see below.  */
   it->stop_charpos = -1;
 
@@ -6618,8 +6618,8 @@ lookup_glyphless_char_display (int c, struct it *it)
       if (c >= 0)
        {
          glyphless_method = CHAR_TABLE_REF (Vglyphless_char_display, c);
-         if (CONSP (glyphless_method))
-           glyphless_method = FRAME_WINDOW_P (it->f)
+      if (CONSP (glyphless_method))
+       glyphless_method = FRAME_WINDOW_P (it->f)
              ? XCAR (glyphless_method)
              : XCDR (glyphless_method);
        }
@@ -6778,8 +6778,8 @@ get_next_display_element (struct it *it)
              if (v->header.size)
                {
                  it->dpvec_char_len = it->len;
-                 it->dpvec = v->u.contents;
-                 it->dpend = v->u.contents + v->header.size;
+                 it->dpvec = v->contents;
+                 it->dpend = v->contents + v->header.size;
                  it->current.dpvec_index = 0;
                  it->dpvec_face_id = -1;
                  it->saved_face_id = it->face_id;
@@ -6807,9 +6807,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.
@@ -6823,7 +6823,7 @@ get_next_display_element (struct it *it)
 
             Non-printable characters and raw-byte characters are also
             translated to octal form.  */
-         if (((c < ' ' || c == 127) /* ASCII control chars */
+         if (((c < ' ' || c == 127) /* ASCII control chars */
               ? (it->area != TEXT_AREA
                  /* In mode line, treat \n, \t like other crl chars.  */
                  || (c != '\t'
@@ -6955,6 +6955,7 @@ get_next_display_element (struct it *it)
        }
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
   /* Adjust face id for a multibyte character.  There are no multibyte
      character in unibyte text.  */
   if ((it->what == IT_CHARACTER || it->what == IT_COMPOSITION)
@@ -6995,6 +6996,7 @@ get_next_display_element (struct it *it)
          it->face_id = FACE_FOR_CHAR (it->f, face, c, pos, it->string);
        }
     }
+#endif /* HAVE_WINDOW_SYSTEM */
 
  done:
   /* Is this character the last one of a run of characters with
@@ -7031,8 +7033,7 @@ get_next_display_element (struct it *it)
                  INC_TEXT_POS (pos, it->multibyte_p);
 
                  next_face_id = face_at_buffer_position
-                   (it->w, CHARPOS (pos), it->region_beg_charpos,
-                    it->region_end_charpos, &ignore,
+                   (it->w, CHARPOS (pos), &ignore,
                     (IT_CHARPOS (*it) + TEXT_PROP_DISTANCE_LIMIT), 0,
                     -1);
                  it->end_of_box_run_p
@@ -7267,12 +7268,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);
        }
@@ -7297,7 +7298,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;
        }
@@ -7809,7 +7810,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);
@@ -7868,7 +7869,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);
@@ -7937,7 +7938,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;
@@ -7983,7 +7984,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;
@@ -8000,7 +8001,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);
@@ -8030,7 +8031,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);
            }
 
@@ -8850,13 +8851,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 (;;)
@@ -8987,6 +8992,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
@@ -8999,12 +9007,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
@@ -9024,15 +9036,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
@@ -9044,6 +9059,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,
@@ -9079,6 +9095,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
       it->current_y += it->max_ascent + it->max_descent;
       ++it->vpos;
       last_height = it->max_ascent + it->max_descent;
+      last_max_ascent = it->max_ascent;
       it->max_ascent = it->max_descent = 0;
     }
 
@@ -9105,12 +9122,15 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
       it->current_y += it->max_ascent + it->max_descent;
       ++it->vpos;
       last_height = it->max_ascent + it->max_descent;
+      last_max_ascent = it->max_ascent;
     }
 
   if (backup_data)
     bidi_unshelve_cache (backup_data, 1);
 
   TRACE_MOVE ((stderr, "move_it_to: reached %d\n", reached));
+
+  return max_current_x;
 }
 
 
@@ -9335,7 +9355,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
 
   /* The commented-out optimization uses vmotion on terminals.  This
      gives bad results, because elements like it->what, on which
-     callers such as pos_visible_p rely, aren't updated. */
+     callers such as pos_visible_p rely, aren't updated.  */
   /* struct position pos;
     if (!FRAME_WINDOW_P (it->f))
     {
@@ -9353,7 +9373,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
     {
       /* DVPOS == 0 means move to the start of the screen line.  */
       move_it_vertically_backward (it, 0);
-      /* Let next call to line_bottom_y calculate real line height */
+      /* Let next call to line_bottom_y calculate real line height */
       last_height = 0;
     }
   else if (dvpos > 0)
@@ -9458,6 +9478,145 @@ 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.
+
+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 any of these lines 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, value;
+  struct buffer *b;
+  struct it it;
+  struct buffer *old_buffer = NULL;
+  ptrdiff_t start, end, pos;
+  struct text_pos startp, endp;
+  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 = XINT (y_limit);
+    }
+
+  itdata = bidi_shelve_cache ();
+  SET_TEXT_POS (startp, start, CHAR_TO_BYTE (start));
+  start_display (&it, w, startp);
+
+  /**   move_it_vertically_backward (&it, 0); **/
+  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 = XINT (x_limit);
+      /* 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);
+    }
+
+  if (start == end)
+    y = it.current_y;
+  else
+    {
+      /* Count last line.  */
+      last_height = 0;
+      y = line_bottom_y (&it); /* - y; */
+    }
+
+  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
@@ -9531,7 +9690,6 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
       ptrdiff_t point_at_end = 0;
       ptrdiff_t zv_at_end = 0;
       Lisp_Object old_deactivate_mark;
-      bool shown;
       struct gcpro gcpro1;
 
       old_deactivate_mark = Vdeactivate_mark;
@@ -9545,12 +9703,13 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
 
         Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
 
-        if (newbuffer &&
-            !NILP (Ffboundp (intern ("messages-buffer-mode"))))
+        if (newbuffer
+           && !NILP (Ffboundp (intern ("messages-buffer-mode"))))
           call0 (intern ("messages-buffer-mode"));
       }
 
       bset_undo_list (current_buffer, Qt);
+      bset_cache_long_scans (current_buffer, Qnil);
 
       oldpoint = message_dolog_marker1;
       set_marker_restricted_both (oldpoint, Qnil, PT, PT_BYTE);
@@ -9687,18 +9846,17 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
       unchain_marker (XMARKER (oldbegv));
       unchain_marker (XMARKER (oldzv));
 
-      shown = buffer_window_count (current_buffer) > 0;
-      set_buffer_internal (oldbuf);
       /* We called insert_1_both above with its 5th argument (PREPARE)
         zero, which prevents insert_1_both from calling
         prepare_to_modify_buffer, which in turns prevents us from
         incrementing windows_or_buffers_changed even if *Messages* is
-        shown in some window.  So we must manually incrementing
+        shown in some window.  So we must manually set
         windows_or_buffers_changed here to make up for that.  */
-      if (shown)
-       windows_or_buffers_changed++;
-      else
        windows_or_buffers_changed = old_windows_or_buffers_changed;
+      bset_redisplay (current_buffer);
+
+      set_buffer_internal (oldbuf);
+
       message_log_need_newline = !nlflag;
       Vdeactivate_mark = old_deactivate_mark;
     }
@@ -9754,7 +9912,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.  */
@@ -9791,7 +9949,11 @@ message3_nolog (Lisp_Object m)
        putc ('\n', stderr);
       noninteractive_need_newline = 0;
       if (STRINGP (m))
-       fwrite (SDATA (m), SBYTES (m), 1, stderr);
+       {
+         Lisp_Object s = ENCODE_SYSTEM (m);
+
+         fwrite (SDATA (s), SBYTES (s), 1, stderr);
+       }
       if (cursor_in_echo_area == 0)
        fprintf (stderr, "\n");
       fflush (stderr);
@@ -9820,7 +9982,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);
@@ -9866,13 +10028,19 @@ 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);
+
          if (noninteractive_need_newline)
            putc ('\n', stderr);
          noninteractive_need_newline = 0;
-         fprintf (stderr, m, SDATA (string));
+         fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string)));
          if (!cursor_in_echo_area)
            fprintf (stderr, "\n");
          fflush (stderr);
+         xfree (fmt);
        }
     }
   else if (INTERACTIVE)
@@ -10087,7 +10255,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.  */
@@ -10104,7 +10272,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];
@@ -10377,20 +10545,13 @@ resize_echo_area_exactly (void)
       && WINDOWP (echo_area_window))
     {
       struct window *w = XWINDOW (echo_area_window);
-      int resized_p;
-      Lisp_Object resize_exactly;
-
-      if (minibuf_level == 0)
-       resize_exactly = Qt;
-      else
-       resize_exactly = Qnil;
-
-      resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
+      Lisp_Object resize_exactly = (minibuf_level == 0 ? Qt : Qnil);
+      int resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
                                         (intptr_t) w, resize_exactly);
       if (resized_p)
        {
-         ++windows_or_buffers_changed;
-         ++update_mode_lines;
+         windows_or_buffers_changed = 42;
+         update_mode_lines = 30;
          redisplay_internal ();
        }
     }
@@ -10452,11 +10613,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;
 
@@ -10470,18 +10630,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;
@@ -10491,7 +10651,6 @@ 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.  */
@@ -10499,7 +10658,7 @@ resize_mini_window (struct window *w, int exact_p)
        {
          height = max_height;
          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);
          start = it.current.pos;
        }
       else
@@ -10510,49 +10669,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;
            }
        }
 
@@ -10737,12 +10896,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)
@@ -10766,7 +10925,6 @@ clear_garbaged_frames (void)
   if (frame_garbaged)
     {
       Lisp_Object tail, frame;
-      int changed_count = 0;
 
       FOR_EACH_FRAME (tail, frame)
        {
@@ -10778,15 +10936,13 @@ clear_garbaged_frames (void)
                redraw_frame (f);
              else
                clear_current_matrices (f);
-             changed_count++;
-             f->garbaged = 0;
-             f->resized_p = 0;
+             fset_redisplay (f);
+             f->garbaged = false;
+             f->resized_p = false;
            }
        }
 
-      frame_garbaged = 0;
-      if (changed_count)
-       ++windows_or_buffers_changed;
+      frame_garbaged = false;
     }
 }
 
@@ -10827,7 +10983,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
@@ -10843,7 +10999,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
@@ -10855,7 +11011,7 @@ echo_area_display (int update_frame_p)
                 pending input.  */
              ptrdiff_t count = SPECPDL_INDEX ();
              specbind (Qredisplay_dont_pause, Qt);
-             windows_or_buffers_changed = 1;
+             windows_or_buffers_changed = 44;
              redisplay_internal ();
              unbind_to (count, Qnil);
            }
@@ -10874,11 +11030,11 @@ echo_area_display (int update_frame_p)
             redisplay displays the minibuffer, so that the cursor will
             be replaced with what the minibuffer wants.  */
          if (cursor_in_echo_area)
-           ++windows_or_buffers_changed;
+           wset_redisplay (XWINDOW (mini_window));
        }
     }
   else if (!EQ (mini_window, selected_window))
-    windows_or_buffers_changed++;
+    wset_redisplay (XWINDOW (mini_window));
 
   /* Last displayed message is now the current message.  */
   echo_area_buffer[1] = echo_area_buffer[0];
@@ -10894,18 +11050,7 @@ echo_area_display (int update_frame_p)
   return window_height_changed_p;
 }
 
-/* Nonzero if the current window's buffer is shown in more than one
-   window and was modified since last redisplay.  */
-
-static int
-buffer_shared_and_changed (void)
-{
-  return (buffer_window_count (current_buffer) > 1
-         && UNCHANGED_MODIFIED < MODIFF);
-}
-
-/* Nonzero if W's buffer was changed but not saved or Transient Mark mode
-   is enabled and mark of W's buffer was changed since last W's update.  */
+/* Nonzero if W's buffer was changed but not saved.  */
 
 static int
 window_buffer_changed (struct window *w)
@@ -10914,9 +11059,7 @@ window_buffer_changed (struct window *w)
 
   eassert (BUFFER_LIVE_P (b));
 
-  return (((BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) != w->last_had_star)
-         || ((!NILP (Vtransient_mark_mode) && !NILP (BVAR (b, mark_active)))
-             != (w->region_showing != 0)));
+  return (((BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) != w->last_had_star));
 }
 
 /* Nonzero if W has %c in its mode line and mode line should be updated.  */
@@ -11219,16 +11362,22 @@ 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.  */
 
-void
+static void
 prepare_menu_bars (void)
 {
-  int all_windows;
+  bool all_windows = windows_or_buffers_changed || update_mode_lines;
+  bool some_windows = REDISPLAY_SOME_P ();
   struct gcpro gcpro1, gcpro2;
-  struct frame *f;
   Lisp_Object tooltip_frame;
 
 #ifdef HAVE_WINDOW_SYSTEM
@@ -11237,17 +11386,45 @@ prepare_menu_bars (void)
   tooltip_frame = Qnil;
 #endif
 
+  if (FUNCTIONP (Vpre_redisplay_function))
+    {
+      Lisp_Object windows = all_windows ? Qt : Qnil;
+      if (all_windows && some_windows)
+       {
+         Lisp_Object ws = window_list ();
+         for (windows = Qnil; CONSP (ws); ws = XCDR (ws))
+           {
+             Lisp_Object this = XCAR (ws);
+             struct window *w = XWINDOW (this);
+             if (w->redisplay
+                 || XFRAME (w->frame)->redisplay
+                 || XBUFFER (w->contents)->text->redisplay)
+               {
+                 windows = Fcons (this, windows);
+               }
+           }
+       }
+      safe_call1 (Vpre_redisplay_function, windows);
+    }
+
   /* Update all frame titles based on their buffer names, etc.  We do
      this before the menu bars so that the buffer-menu will show the
      up-to-date frame titles.  */
 #ifdef HAVE_WINDOW_SYSTEM
-  if (windows_or_buffers_changed || update_mode_lines)
+  if (all_windows)
     {
       Lisp_Object tail, frame;
 
       FOR_EACH_FRAME (tail, frame)
        {
-         f = XFRAME (frame);
+         struct frame *f = XFRAME (frame);
+         struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+         if (some_windows
+             && !f->redisplay
+             && !w->redisplay
+             && !XBUFFER (w->contents)->text->redisplay)
+           continue;
+
          if (!EQ (frame, tooltip_frame)
              && (FRAME_ICONIFIED_P (f)
                  || FRAME_VISIBLE_P (f) == 1
@@ -11268,9 +11445,7 @@ prepare_menu_bars (void)
 
   /* Update the menu bar item lists, if appropriate.  This has to be
      done before any actual redisplay or generation of display lines.  */
-  all_windows = (update_mode_lines
-                || buffer_shared_and_changed ()
-                || windows_or_buffers_changed);
+
   if (all_windows)
     {
       Lisp_Object tail, frame;
@@ -11283,12 +11458,19 @@ prepare_menu_bars (void)
 
       FOR_EACH_FRAME (tail, frame)
        {
-         f = XFRAME (frame);
+         struct frame *f = XFRAME (frame);
+         struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
 
          /* Ignore tooltip frame.  */
          if (EQ (frame, tooltip_frame))
            continue;
 
+         if (some_windows
+             && !f->redisplay
+             && !w->redisplay
+             && !XBUFFER (w->contents)->text->redisplay)
+           continue;
+
          /* If a window on this frame changed size, report that to
             the user and clear the size-change flag.  */
          if (FRAME_WINDOW_SIZES_CHANGED (f))
@@ -11483,8 +11665,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)
@@ -11866,7 +12048,8 @@ 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)))
@@ -11876,11 +12059,11 @@ display_tool_bar_line (struct it *it, int height)
    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);
@@ -11889,6 +12072,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;
+  /* PXW: Use FRAME_PIXEL_WIDTH (f) here ?  */
   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
   reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
   it.paragraph_embedding = L2R;
@@ -11905,7 +12089,10 @@ 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 */
@@ -11914,30 +12101,30 @@ tool_bar_lines_needed (struct frame *f, int *n_rows)
 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 inpixels.  */)
+  (Lisp_Object frame, Lisp_Object pixelwise)
 {
-  int nlines = 0;
-#if ! defined (USE_GTK) && ! defined (HAVE_NS)
   struct frame *f = decode_any_frame (frame);
-  struct window *w;
+  int height = 0;
 
+#if ! defined (USE_GTK) && ! defined (HAVE_NS)
   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);
 }
 
 
@@ -11965,13 +12152,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.  */
@@ -11988,24 +12175,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;
        }
     }
 
@@ -12054,6 +12239,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;
 
@@ -12084,29 +12270,29 @@ 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)
            {
+             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->n_tool_bar_rows = nrows;
-                 f->fonts_changed = 1;
-                 return 1;
-               }
+                                                     make_number (new_lines))));
+             /* Always do that now.  */
+             clear_glyph_matrix (w->desired_matrix);
+             f->n_tool_bar_rows = nrows;
+             f->fonts_changed = 1;
+             return 1;
            }
        }
     }
@@ -12435,7 +12621,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)
@@ -12452,7 +12638,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
@@ -12911,6 +13097,28 @@ reconsider_clip_changes (struct window *w)
     }
 }
 
+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
+     unredisplayed for a long time if it's currently invisible.
+     But we do want to reset it at the end of redisplay otherwise
+     its displayed windows will keep being redisplayed over and over
+     again.
+     So we copy all b->text->redisplay flags up to their windows here,
+     such that mark_window_display_accurate can safely reset
+     b->text->redisplay.  */
+  Lisp_Object ws = window_list ();
+  for (; CONSP (ws); ws = XCDR (ws))
+    {
+      struct window *thisw = XWINDOW (XCAR (ws));
+      struct buffer *thisb = XBUFFER (thisw->contents);
+      if (thisb->text->redisplay)
+       thisw->redisplay = true;
+    }
+}
+
 #define STOP_POLLING                                   \
 do { if (! polling_stopped_here) stop_polling ();      \
        polling_stopped_here = 1; } while (0)
@@ -12938,12 +13146,12 @@ redisplay_internal (void)
   int polling_stopped_here = 0;
   Lisp_Object tail, frame;
 
-  /* Non-zero means redisplay has to consider all windows on all
-     frames.  Zero means, only selected_window is considered.  */
-  int consider_all_windows_p;
+  /* True means redisplay has to consider all windows on all
+     frames.  False, only selected_window is considered.  */
+  bool consider_all_windows_p;
 
-  /* Non-zero means redisplay has to redisplay the miniwindow.  */
-  int update_miniwindow_p = 0;
+  /* True means redisplay has to redisplay the miniwindow.  */
+  bool update_miniwindow_p = false;
 
   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
 
@@ -12999,7 +13207,7 @@ redisplay_internal (void)
      realized faces, which includes the faces referenced from current
      matrices.  So, we can't reuse current matrices in this case.  */
   if (face_change_count)
-    ++windows_or_buffers_changed;
+    windows_or_buffers_changed = 47;
 
   if ((FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))
       && FRAME_TTY (sf)->previous_frame != sf)
@@ -13007,7 +13215,6 @@ redisplay_internal (void)
       /* Since frames on a single ASCII terminal share the same
         display area, displaying a different frame means redisplay
         the whole thing.  */
-      windows_or_buffers_changed++;
       SET_FRAME_GARBAGED (sf);
 #ifndef DOS_NT
       set_tty_color_mode (FRAME_TTY (sf), sf);
@@ -13036,7 +13243,7 @@ redisplay_internal (void)
          /* If cursor type has been changed on the frame
             other than selected, consider all frames.  */
          if (f != sf && f->cursor_type_changed)
-           update_mode_lines++;
+           update_mode_lines = 31;
        }
       clear_desired_matrices (f);
     }
@@ -13056,43 +13263,20 @@ redisplay_internal (void)
   if (NILP (Vmemory_full))
     prepare_menu_bars ();
 
-  if (windows_or_buffers_changed)
-    update_mode_lines++;
-
   reconsider_clip_changes (w);
 
   /* In most cases selected window displays current buffer.  */
   match_p = XBUFFER (w->contents) == current_buffer;
   if (match_p)
     {
-      ptrdiff_t count1;
-
       /* Detect case that we need to write or remove a star in the mode line.  */
       if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
-       {
          w->update_mode_line = 1;
-         if (buffer_shared_and_changed ())
-           update_mode_lines++;
-       }
-
-      /* Avoid invocation of point motion hooks by `current_column' below.  */
-      count1 = SPECPDL_INDEX ();
-      specbind (Qinhibit_point_motion_hooks, Qt);
 
       if (mode_line_update_needed (w))
        w->update_mode_line = 1;
-
-      unbind_to (count1, Qnil);
     }
 
-  consider_all_windows_p = (update_mode_lines
-                           || buffer_shared_and_changed ());
-
-  /* If specs for an arrow have changed, do thorough redisplay
-     to ensure we remove any arrow that should no longer exist.  */
-  if (overlay_arrows_changed_p ())
-    consider_all_windows_p = windows_or_buffers_changed = 1;
-
   /* Normally the message* functions will have already displayed and
      updated the echo area, but the frame may have been trashed, or
      the update may have been preempted, so display the echo area
@@ -13109,7 +13293,7 @@ redisplay_internal (void)
       int window_height_changed_p = echo_area_display (0);
 
       if (message_cleared_p)
-       update_miniwindow_p = 1;
+       update_miniwindow_p = true;
 
       must_finish = 1;
 
@@ -13122,9 +13306,7 @@ redisplay_internal (void)
 
       if (window_height_changed_p)
        {
-         consider_all_windows_p = 1;
-         ++update_mode_lines;
-         ++windows_or_buffers_changed;
+         windows_or_buffers_changed = 50;
 
          /* If window configuration was changed, frames may have been
             marked garbaged.  Clear them or we will experience
@@ -13139,13 +13321,6 @@ redisplay_internal (void)
       /* Resized active mini-window to fit the size of what it is
          showing if its contents might have changed.  */
       must_finish = 1;
-      /* FIXME: this causes all frames to be updated, which seems unnecessary
-        since only the current frame needs to be considered.  This function
-        needs to be rewritten with two variables, consider_all_windows and
-        consider_all_frames.  */
-      consider_all_windows_p = 1;
-      ++windows_or_buffers_changed;
-      ++update_mode_lines;
 
       /* If window configuration was changed, frames may have been
         marked garbaged.  Clear them or we will experience
@@ -13153,16 +13328,29 @@ redisplay_internal (void)
       clear_garbaged_frames ();
     }
 
-  /* If showing the region, and mark has changed, we must redisplay
-     the whole window.  The assignment to this_line_start_pos prevents
-     the optimization directly below this if-statement.  */
-  if (((!NILP (Vtransient_mark_mode)
-       && !NILP (BVAR (XBUFFER (w->contents), mark_active)))
-       != (w->region_showing > 0))
-      || (w->region_showing
-         && w->region_showing
-         != XINT (Fmarker_position (BVAR (XBUFFER (w->contents), mark)))))
-    CHARPOS (this_line_start_pos) = 0;
+  if (windows_or_buffers_changed && !update_mode_lines)
+    /* Code that sets windows_or_buffers_changed doesn't distinguish whether
+       only the windows's contents needs to be refreshed, or whether the
+       mode-lines also need a refresh.  */
+    update_mode_lines = (windows_or_buffers_changed == REDISPLAY_SOME
+                        ? REDISPLAY_SOME : 32);
+
+  /* If specs for an arrow have changed, do thorough redisplay
+     to ensure we remove any arrow that should no longer exist.  */
+  if (overlay_arrows_changed_p ())
+    /* Apparently, this is the only case where we update other windows,
+       without updating other mode-lines.  */
+    windows_or_buffers_changed = 49;
+
+  consider_all_windows_p = (update_mode_lines
+                           || windows_or_buffers_changed);
+
+#define AINC(a,i) \
+  if (VECTORP (a) && i >= 0 && i < ASIZE (a) && INTEGERP (AREF (a, i))) \
+    ASET (a, i, make_number (1 + XINT (AREF (a, i))))
+
+  AINC (Vredisplay__all_windows_cause, windows_or_buffers_changed);
+  AINC (Vredisplay__mode_lines_cause, update_mode_lines);
 
   /* Optimize the case that only the line containing the cursor in the
      selected window has changed.  Variables starting with this_ are
@@ -13303,6 +13491,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 pixelized, probably.  */
               && 0 <= w->cursor.vpos
               && w->cursor.vpos < WINDOW_TOTAL_LINES (w))
        {
@@ -13323,13 +13513,7 @@ redisplay_internal (void)
        }
       /* If highlighting the region, or if the cursor is in the echo area,
         then we can't just move the cursor.  */
-      else if (! (!NILP (Vtransient_mark_mode)
-                 && !NILP (BVAR (current_buffer, mark_active)))
-              && (EQ (selected_window,
-                      BVAR (current_buffer, last_selected_window))
-                  || highlight_nonselected_windows)
-              && !w->region_showing
-              && NILP (Vshow_trailing_whitespace)
+      else if (NILP (Vshow_trailing_whitespace)
               && !cursor_in_echo_area)
        {
          struct it it;
@@ -13371,7 +13555,6 @@ redisplay_internal (void)
     }
 
   CHARPOS (this_line_start_pos) = 0;
-  consider_all_windows_p |= buffer_shared_and_changed ();
   ++clear_face_cache_count;
 #ifdef HAVE_WINDOW_SYSTEM
   ++clear_image_cache_count;
@@ -13386,6 +13569,8 @@ redisplay_internal (void)
       FOR_EACH_FRAME (tail, frame)
        XFRAME (frame)->updated_p = 0;
 
+      propagate_buffer_redisplay ();
+
       FOR_EACH_FRAME (tail, frame)
        {
          struct frame *f = XFRAME (frame);
@@ -13400,13 +13585,20 @@ 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 || !REDISPLAY_SOME_P ();
              /* Mark all the scroll bars to be removed; we'll redeem
                 the ones we want when we redisplay their windows.  */
-             if (FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
+             if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook)
                FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f);
 
              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))
@@ -13414,7 +13606,7 @@ redisplay_internal (void)
 
              /* Any scroll bars which redisplay_windows should have
                 nuked should now go away.  */
-             if (FRAME_TERMINAL (f)->judge_scroll_bars_hook)
+             if (gcscrollbars && FRAME_TERMINAL (f)->judge_scroll_bars_hook)
                FRAME_TERMINAL (f)->judge_scroll_bars_hook (f);
 
              if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
@@ -13437,14 +13629,11 @@ redisplay_internal (void)
 
                  /* Prevent various kinds of signals during display
                     update.  stdio is not robust about handling
-                    signals, which can cause an apparent I/O
-                    error.  */
+                    signals, which can cause an apparent I/O error.  */
                  if (interrupt_input)
                    unrequest_sigio ();
                  STOP_POLLING;
 
-                 /* Update the display.  */
-                 set_window_update_flags (XWINDOW (f->root_window), 1);
                  pending |= update_frame (f, 0, 0);
                  f->cursor_type_changed = 0;
                  f->updated_p = 1;
@@ -13464,6 +13653,7 @@ redisplay_internal (void)
              struct frame *f = XFRAME (frame);
               if (f->updated_p)
                 {
+                 f->redisplay = false;
                   mark_window_display_accurate (f->root_window, 1);
                   if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
                     FRAME_TERMINAL (f)->frame_up_to_date_hook (f);
@@ -13506,7 +13696,7 @@ redisplay_internal (void)
          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;
        }
@@ -13521,7 +13711,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))
@@ -13545,7 +13735,7 @@ redisplay_internal (void)
         matrices of some windows are not valid.  */
       if (!WINDOW_FULL_WIDTH_P (w)
          && !FRAME_WINDOW_P (XFRAME (w->frame)))
-       update_mode_lines = 1;
+       update_mode_lines = 36;
     }
   else
     {
@@ -13553,6 +13743,11 @@ redisplay_internal (void)
        {
          /* This has already been done above if
             consider_all_windows_p is set.  */
+         if (XBUFFER (w->contents)->text->redisplay
+             && buffer_window_count (XBUFFER (w->contents)) > 1)
+           /* This can happen if b->text->redisplay was set during
+              jit-lock.  */
+           propagate_buffer_redisplay ();
          mark_window_display_accurate_1 (w, 1);
 
          /* Say overlay arrows are up to date.  */
@@ -13586,17 +13781,12 @@ redisplay_internal (void)
 
       FOR_EACH_FRAME (tail, frame)
        {
-         int this_is_visible = 0;
-
          if (XFRAME (frame)->visible)
-           this_is_visible = 1;
-
-         if (this_is_visible)
            new_count++;
        }
 
       if (new_count != number_of_visible_frames)
-       windows_or_buffers_changed++;
+       windows_or_buffers_changed = 52;
     }
 
   /* Change frame size now if a change is pending.  */
@@ -13690,8 +13880,13 @@ mark_window_display_accurate_1 (struct window *w, int accurate_p)
 
   if (accurate_p)
     {
-      b->clip_changed = 0;
-      b->prevent_redisplay_optimizations_p = 0;
+      b->clip_changed = false;
+      b->prevent_redisplay_optimizations_p = false;
+      eassert (buffer_window_count (b) > 0);
+      /* Resetting b->text->redisplay is problematic!
+        In order to make it safer to do it here, redisplay_internal must
+        have copied all b->text->redisplay to their respective windows.  */
+      b->text->redisplay = false;
 
       BUF_UNCHANGED_MODIFIED (b) = BUF_MODIFF (b);
       BUF_OVERLAY_UNCHANGED_MODIFIED (b) = BUF_OVERLAY_MODIFF (b);
@@ -13710,9 +13905,11 @@ mark_window_display_accurate_1 (struct window *w, int accurate_p)
       else
        w->last_point = marker_position (w->pointm);
 
-      w->window_end_valid = 1;
-      w->update_mode_line = 0;
+      w->window_end_valid = true;
+      w->update_mode_line = false;
     }
+
+  w->redisplay = !accurate_p;
 }
 
 
@@ -13815,7 +14012,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;
 }
 
@@ -13823,7 +14020,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
@@ -14365,9 +14562,9 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
      occlude point.  Only set w->cursor if we found a better
      approximation to the cursor position than we have from previously
      examined candidate rows belonging to the same continued line.  */
-  if (/* we already have a candidate row */
+  if (/* We already have a candidate row.  */
       w->cursor.vpos >= 0
-      /* that candidate is not the row we are processing */
+      /* That candidate is not the row we are processing.  */
       && MATRIX_ROW (matrix, w->cursor.vpos) != row
       /* Make sure cursor.vpos specifies a row whose start and end
         charpos occlude point, and it is valid candidate for being a
@@ -14378,30 +14575,30 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
       && pt_old <= MATRIX_ROW_END_CHARPOS (MATRIX_ROW (matrix, w->cursor.vpos))
       && cursor_row_p (MATRIX_ROW (matrix, w->cursor.vpos)))
     {
-      struct glyph *g1 =
-       MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos;
+      struct glyph *g1
+       MATRIX_ROW_GLYPH_START (matrix, w->cursor.vpos) + w->cursor.hpos;
 
       /* Don't consider glyphs that are outside TEXT_AREA.  */
       if (!(row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end))
        return 0;
       /* Keep the candidate whose buffer position is the closest to
         point or has the `cursor' property.  */
-      if (/* previous candidate is a glyph in TEXT_AREA of that row */
+      if (/* Previous candidate is a glyph in TEXT_AREA of that row.  */
          w->cursor.hpos >= 0
          && w->cursor.hpos < MATRIX_ROW_USED (matrix, w->cursor.vpos)
          && ((BUFFERP (g1->object)
-              && (g1->charpos == pt_old /* an exact match always wins */
+              && (g1->charpos == pt_old /* An exact match always wins.  */
                   || (BUFFERP (glyph->object)
                       && eabs (g1->charpos - pt_old)
                       < eabs (glyph->charpos - pt_old))))
-             /* previous candidate is a glyph from a string that has
-                a non-nil `cursor' property */
+             /* Previous candidate is a glyph from a string that has
+                a non-nil `cursor' property */
              || (STRINGP (g1->object)
                  && (!NILP (Fget_char_property (make_number (g1->charpos),
                                                Qcursor, g1->object))
-                     /* previous candidate is from the same display
+                     /* Previous candidate is from the same display
                         string as this one, and the display string
-                        came from a text property */
+                        came from a text property */
                      || (EQ (g1->object, glyph->object)
                          && string_from_text_prop)
                      /* this candidate is from newline and its
@@ -14899,6 +15096,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;
@@ -15004,11 +15202,6 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
       && !update_mode_lines
       && !windows_or_buffers_changed
       && !f->cursor_type_changed
-      /* Can't use this case if highlighting a region.  When a
-         region exists, cursor movement has to do more than just
-         set the cursor.  */
-      && markpos_of_region () < 0
-      && !w->region_showing
       && NILP (Vshow_trailing_whitespace)
       /* This code is not used for mini-buffer for the sake of the case
         of redisplaying to replace an echo area message; since in
@@ -15354,7 +15547,7 @@ set_vertical_scroll_bar (struct window *w)
    changed on window's frame.  In that case, redisplay_internal will retry.  */
 
 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);
@@ -15365,11 +15558,11 @@ 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;
@@ -15385,6 +15578,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   *w->desired_matrix->method = 0;
 #endif
 
+  if (!just_this_one_p
+      && REDISPLAY_SOME_P ()
+      && !w->redisplay
+      && !f->redisplay
+      && !buffer->text->redisplay)
+    return;
+
   /* Make sure that both W's markers are valid.  */
   eassert (XMARKER (w->start)->buffer == buffer);
   eassert (XMARKER (w->pointm)->buffer == buffer);
@@ -15399,6 +15599,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)
@@ -15414,7 +15619,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        }
       else if ((w != XWINDOW (minibuf_window)
                || minibuf_level == 0)
-              /* When buffer is nonempty, redisplay window normally. */
+              /* When buffer is nonempty, redisplay window normally.  */
               && BUF_Z (XBUFFER (w->contents)) == BUF_BEG (XBUFFER (w->contents))
               /* Quail displays non-mini buffers in minibuffer window.
                  In that case, redisplay the window normally.  */
@@ -15479,10 +15684,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.  */
@@ -15623,7 +15828,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
             Move it back to a fully-visible line.  */
          new_vpos = window_box_height (w);
        }
-      else if (w->cursor.vpos >=0)
+      else if (w->cursor.vpos >= 0)
        {
          /* Some people insist on not letting point enter the scroll
             margin, even though this part handles windows that didn't
@@ -15681,12 +15886,14 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
          /* If we are highlighting the region, then we just changed
             the region, so redisplay to show it.  */
-         if (markpos_of_region () >= 0)
+         /* FIXME: We need to (re)run pre-redisplay-function!  */
+         /* if (markpos_of_region () >= 0)
            {
              clear_glyph_matrix (w->desired_matrix);
              if (!try_window (window, startp, 0))
                goto need_larger_matrices;
            }
+         */
        }
 
 #ifdef GLYPH_DEBUG
@@ -16098,7 +16305,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
@@ -16118,6 +16325,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
@@ -16183,7 +16391,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;
@@ -16201,10 +16409,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
@@ -16238,7 +16454,7 @@ 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));
 
@@ -16381,10 +16597,8 @@ try_window_reusing_current_matrix (struct window *w)
       || f->cursor_type_changed)
     return 0;
 
-  /* Can't do this if region may have changed.  */
-  if (markpos_of_region () >= 0
-      || w->region_showing
-      || !NILP (Vshow_trailing_whitespace))
+  /* Can't do this if showing trailing whitespace.  */
+  if (!NILP (Vshow_trailing_whitespace))
     return 0;
 
   /* If top-line visibility has changed, give up.  */
@@ -17182,19 +17396,10 @@ try_window_id (struct window *w)
   if (!w->window_end_valid)
     GIVE_UP (8);
 
-  /* Can't use this if highlighting a region because a cursor movement
-     will do more than just set the cursor.  */
-  if (markpos_of_region () >= 0)
-    GIVE_UP (9);
-
   /* Likewise if highlighting trailing whitespace.  */
   if (!NILP (Vshow_trailing_whitespace))
     GIVE_UP (11);
 
-  /* Likewise if showing a region.  */
-  if (w->region_showing)
-    GIVE_UP (10);
-
   /* Can't use this if overlay arrow position and/or string have
      changed.  */
   if (overlay_arrows_changed_p ())
@@ -18538,7 +18743,7 @@ append_space_for_newline (struct it *it, int default_face_p)
          it->len = 1;
 
          /* If the default face was remapped, be sure to use the
-            remapped face for the appended newline. */
+            remapped face for the appended newline.  */
          if (default_face_p)
            it->face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
          else if (it->face_before_selective_p)
@@ -18616,7 +18821,9 @@ extend_face_to_end_of_line (struct it *it)
       && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row)
       && face->box == FACE_NO_BOX
       && face->background == FRAME_BACKGROUND_PIXEL (f)
+#ifdef HAVE_WINDOW_SYSTEM
       && !face->stipple
+#endif
       && !it->glyph_row->reversed_p)
     return;
 
@@ -19276,9 +19483,6 @@ display_line (struct it *it)
       return 0;
     }
 
-  /* Is IT->w showing the region?  */
-  it->w->region_showing = it->region_beg_charpos > 0 ? it->region_beg_charpos : 0;
-
   /* Clear the result glyph row and enable it.  */
   prepare_desired_row (row);
 
@@ -20519,6 +20723,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;
+  /* PXW: Use FRAME_PIXEL_WIDTH (f) here ?  */
   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
 #elif defined (HAVE_X_WINDOWS) /* X without toolkit.  */
   if (FRAME_WINDOW_P (f))
@@ -20530,6 +20735,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;
+      /* PXW: Use FRAME_PIXEL_WIDTH (f) here ?  */
       it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
     }
   else
@@ -20585,7 +20791,127 @@ display_menu_bar (struct window *w)
   compute_line_metrics (&it);
 }
 
+/* Deep copy of a glyph row, including the glyphs.  */
+static void
+deep_copy_glyph_row (struct glyph_row *to, struct glyph_row *from)
+{
+  struct glyph *pointers[1 + LAST_AREA];
+  int to_used = to->used[TEXT_AREA];
+
+  /* Save glyph pointers of TO.  */
+  memcpy (pointers, to->glyphs, sizeof to->glyphs);
+
+  /* Do a structure assignment.  */
+  *to = *from;
+
+  /* Restore original glyph pointers of TO.  */
+  memcpy (to->glyphs, pointers, sizeof to->glyphs);
+
+  /* Copy the glyphs.  */
+  memcpy (to->glyphs[TEXT_AREA], from->glyphs[TEXT_AREA],
+         min (from->used[TEXT_AREA], to_used) * sizeof (struct glyph));
 
+  /* If we filled only part of the TO row, fill the rest with
+     space_glyph (which will display as empty space).  */
+  if (to_used > from->used[TEXT_AREA])
+    fill_up_frame_row_with_spaces (to, to_used);
+}
+
+/* Display one menu item on a TTY, by overwriting the glyphs in the
+   frame F's desired glyph matrix with glyphs produced from the menu
+   item text.  Called from term.c to display TTY drop-down menus one
+   item at a time.
+
+   ITEM_TEXT is the menu item text as a C string.
+
+   FACE_ID is the face ID to be used for this menu item.  FACE_ID
+   could specify one of 3 faces: a face for an enabled item, a face
+   for a disabled item, or a face for a selected item.
+
+   X and Y are coordinates of the first glyph in the frame's desired
+   matrix to be overwritten by the menu item.  Since this is a TTY, Y
+   is the zero-based number of the glyph row and X is the zero-based
+   glyph number in the row, starting from left, where to start
+   displaying the item.
+
+   SUBMENU non-zero means this menu item drops down a submenu, which
+   should be indicated by displaying a proper visual cue after the
+   item text.  */
+
+void
+display_tty_menu_item (const char *item_text, int width, int face_id,
+                      int x, int y, int submenu)
+{
+  struct it it;
+  struct frame *f = SELECTED_FRAME ();
+  struct window *w = XWINDOW (f->selected_window);
+  int saved_used, saved_truncated, saved_width, saved_reversed;
+  struct glyph_row *row;
+  size_t item_len = strlen (item_text);
+
+  eassert (FRAME_TERMCAP_P (f));
+
+  /* Don't write beyond the matrix's last row.  This can happen for
+     TTY screens that are not high enough to show the entire menu.
+     (This is actually a bit of defensive programming, as
+     tty_menu_display already limits the number of menu items to one
+     less than the number of screen lines.)  */
+  if (y >= f->desired_matrix->nrows)
+    return;
+
+  init_iterator (&it, w, -1, -1, f->desired_matrix->rows + y, MENU_FACE_ID);
+  it.first_visible_x = 0;
+  it.last_visible_x = FRAME_COLS (f) - 1;
+  row = it.glyph_row;
+  /* Start with the row contents from the current matrix.  */
+  deep_copy_glyph_row (row, f->current_matrix->rows + y);
+  saved_width = row->full_width_p;
+  row->full_width_p = 1;
+  saved_reversed = row->reversed_p;
+  row->reversed_p = 0;
+  row->enabled_p = 1;
+
+  /* Arrange for the menu item glyphs to start at (X,Y) and have the
+     desired face.  */
+  eassert (x < f->desired_matrix->matrix_w);
+  it.current_x = it.hpos = x;
+  it.current_y = it.vpos = y;
+  saved_used = row->used[TEXT_AREA];
+  saved_truncated = row->truncated_on_right_p;
+  row->used[TEXT_AREA] = x;
+  it.face_id = face_id;
+  it.line_wrap = TRUNCATE;
+
+  /* FIXME: This should be controlled by a user option.  See the
+     comments in redisplay_tool_bar and display_mode_line about this.
+     Also, if paragraph_embedding could ever be R2L, changes will be
+     needed to avoid shifting to the right the row characters in
+     term.c:append_glyph.  */
+  it.paragraph_embedding = L2R;
+
+  /* Pad with a space on the left.  */
+  display_string (" ", Qnil, Qnil, 0, 0, &it, 1, 0, FRAME_COLS (f) - 1, -1);
+  width--;
+  /* Display the menu item, pad with spaces to WIDTH.  */
+  if (submenu)
+    {
+      display_string (item_text, Qnil, Qnil, 0, 0, &it,
+                     item_len, 0, FRAME_COLS (f) - 1, -1);
+      width -= item_len;
+      /* Indicate with " >" that there's a submenu.  */
+      display_string (" >", Qnil, Qnil, 0, 0, &it, width, 0,
+                     FRAME_COLS (f) - 1, -1);
+    }
+  else
+    display_string (item_text, Qnil, Qnil, 0, 0, &it,
+                   width, 0, FRAME_COLS (f) - 1, -1);
+
+  row->used[TEXT_AREA] = max (saved_used, row->used[TEXT_AREA]);
+  row->truncated_on_right_p = saved_truncated;
+  row->hash = row_hash (row);
+  row->full_width_p = saved_width;
+  row->reversed_p = saved_reversed;
+}
 \f
 /***********************************************************************
                              Mode Line
@@ -20597,7 +20923,7 @@ display_menu_bar (struct window *w)
    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;
 
@@ -20631,10 +20957,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);
@@ -20690,6 +21013,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;
 }
 
@@ -22290,9 +22615,7 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st
 
       it->face_id
        = face_at_string_position (it->w, face_string, face_string_pos,
-                                  0, it->region_beg_charpos,
-                                  it->region_end_charpos,
-                                  &endptr, it->base_face_id, 0);
+                                  0, &endptr, it->base_face_id, 0);
       face = FACE_FROM_ID (it->f, it->face_id);
       it->face_box_p = face->box != FACE_NO_BOX;
     }
@@ -23787,7 +24110,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
     {
@@ -25019,7 +25343,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
       lower_yoff = descent - 2 - metrics_lower.descent;
       upper_yoff = (lower_yoff - metrics_lower.ascent - 1
                    - metrics_upper.descent);
-      /* Don't make the height shorter than the base height. */
+      /* Don't make the height shorter than the base height.  */
       if (height > base_height)
        {
          it->ascent = ascent;
@@ -25056,16 +25380,16 @@ x_produce_glyphs (struct it *it)
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       struct font *font = face->font;
       struct font_metrics *pcm = NULL;
-      int boff;                        /* baseline offset */
+      int boff;                        /* Baseline offset.  */
 
       if (font == NULL)
        {
          /* When no suitable font is found, display this character by
             the method specified in the first extra slot of
             Vglyphless_char_display.  */
-         Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
+             Lisp_Object acronym = lookup_glyphless_char_display (-1, it);
 
-         eassert (it->what == IT_GLYPHLESS);
+             eassert (it->what == IT_GLYPHLESS);
          produce_glyphless_glyph (it, 1, STRINGP (acronym) ? acronym : Qnil);
          goto done;
        }
@@ -25203,7 +25527,7 @@ x_produce_glyphs (struct it *it)
        {
          /* A newline has no width, but we need the height of the
             line.  But if previous part of the line sets a height,
-            don't increase that height */
+            don't increase that height */
 
          Lisp_Object height;
          Lisp_Object total_height = Qnil;
@@ -25213,7 +25537,7 @@ x_produce_glyphs (struct it *it)
          it->nglyphs = 0;
 
          height = get_it_property (it, Qline_height);
-         /* Split (line-height total-height) list */
+         /* Split (line-height total-height) list */
          if (CONSP (height)
              && CONSP (XCDR (height))
              && NILP (XCDR (XCDR (height))))
@@ -25825,7 +26149,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);
@@ -26289,9 +26614,11 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
 }
 
 
-/* EXPORT:
-   Erase the image of a cursor of window W from the screen.  */
+/* 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 +27067,10 @@ 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;
 }
 
@@ -27294,7 +27624,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
 
   hlinfo->mouse_face_window = window;
   hlinfo->mouse_face_face_id
-    = face_at_buffer_position (w, mouse_charpos, 0, 0, &ignore,
+    = face_at_buffer_position (w, mouse_charpos, &ignore,
                               mouse_charpos + 1,
                               !hlinfo->mouse_face_hidden, -1);
   show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
@@ -27560,7 +27890,7 @@ on_hot_spot_p (Lisp_Object hot_spot, int x, int y)
       if (VECTORP (XCDR (hot_spot)))
        {
          struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
-         Lisp_Object *poly = v->u.contents;
+         Lisp_Object *poly = v->contents;
          ptrdiff_t n = v->header.size;
          ptrdiff_t i;
          int inside = 0;
@@ -27664,6 +27994,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;
@@ -27975,8 +28307,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 
          hlinfo->mouse_face_face_id = face_at_string_position (w, string,
                                                                charpos,
-                                                               0, 0, 0,
-                                                               &ignore,
+                                                               0, &ignore,
                                                                glyph->face_id,
                                                                1);
          show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
@@ -28078,6 +28409,16 @@ 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)
+    {
+      cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor;
+      help_echo_string = build_string ("drag-mouse-1: resize");
+    }
   else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
           || part == ON_SCROLL_BAR)
     cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
@@ -28277,7 +28618,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
              hlinfo->mouse_face_past_end = 0;
              hlinfo->mouse_face_window = window;
              hlinfo->mouse_face_face_id
-               = face_at_string_position (w, object, pos, 0, 0, 0, &ignore,
+               = face_at_string_position (w, object, pos, 0, &ignore,
                                           glyph->face_id, 1);
              show_mouse_face (hlinfo, DRAW_MOUSE_FACE);
              cursor = No_Cursor;
@@ -28324,13 +28665,14 @@ note_mouse_highlight (struct frame *f, int x, int y)
                     the first row visible in a window does not
                     necessarily display the character whose position
                     is the smallest.  */
-                 Lisp_Object lim1 =
-                   NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
+                 Lisp_Object lim1
+                   NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
                    ? Fmarker_position (w->start)
                    : Qnil;
-                 Lisp_Object lim2 =
-                   NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
-                   ? make_number (BUF_Z (XBUFFER (buffer)) - w->window_end_pos)
+                 Lisp_Object lim2
+                   = NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
+                   ? make_number (BUF_Z (XBUFFER (buffer))
+                                  - w->window_end_pos)
                    : Qnil;
 
                  if (NILP (overlay))
@@ -28717,7 +29059,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
@@ -28736,6 +29078,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))
     {
@@ -28752,6 +29095,44 @@ 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);
+      int y1 = WINDOW_BOTTOM_EDGE_Y (w);
+
+      FRAME_RIF (f)->draw_window_divider (w, x0, x1, y0, y1);
+    }
+}
+
+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
@@ -28783,8 +29164,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))
     {
@@ -28880,7 +29261,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
@@ -29098,13 +29485,14 @@ syms_of_xdisp (void)
   defsubr (&Strace_to_stderr);
 #endif
 #ifdef HAVE_WINDOW_SYSTEM
-  defsubr (&Stool_bar_lines_needed);
+  defsubr (&Stool_bar_height);
   defsubr (&Slookup_image_map);
 #endif
   defsubr (&Sline_pixel_height);
   defsubr (&Sformat_mode_line);
   defsubr (&Sinvisible_p);
   defsubr (&Scurrent_bidi_paragraph_direction);
+  defsubr (&Swindow_text_pixel_size);
   defsubr (&Smove_point_visually);
 
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
@@ -29663,6 +30051,13 @@ cursor shapes.  */);
   DEFSYM (Qthin_space, "thin-space");
   DEFSYM (Qzero_width, "zero-width");
 
+  DEFVAR_LISP ("pre-redisplay-function", Vpre_redisplay_function,
+              doc: /* Function run just before redisplay.
+It is called with one argument, which is the set of windows that are to
+be redisplayed.  This set can be nil (meaning, only the selected window),
+or t (meaning all windows).  */);
+  Vpre_redisplay_function = intern ("ignore");
+
   DEFSYM (Qglyphless_char_display, "glyphless-char-display");
   Fput (Qglyphless_char_display, Qchar_table_extra_slots, make_number (1));
 
@@ -29681,7 +30076,11 @@ GRAPHICAL and TEXT should each have one of the values listed above.
 The char-table has one extra slot to control the display of a character for
 which no font is found.  This slot only takes effect on graphical terminals.
 Its value should be an ASCII acronym string, `hex-code', `empty-box', or
-`thin-space'.  The default is `empty-box'.  */);
+`thin-space'.  The default is `empty-box'.
+
+If a character has a non-nil entry in an active display table, the
+display table takes effect; in this case, Emacs does not consult
+`glyphless-char-display' at all.  */);
   Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
   Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
                              Qempty_box);
@@ -29689,6 +30088,16 @@ Its value should be an ASCII acronym string, `hex-code', `empty-box', or
   DEFVAR_LISP ("debug-on-message", Vdebug_on_message,
               doc: /* If non-nil, debug if a message matching this regexp is displayed.  */);
   Vdebug_on_message = Qnil;
+
+  DEFVAR_LISP ("redisplay--all-windows-cause", Vredisplay__all_windows_cause,
+              doc: /*  */);
+  Vredisplay__all_windows_cause
+    = Fmake_vector (make_number (100), make_number (0));
+
+  DEFVAR_LISP ("redisplay--mode-lines-cause", Vredisplay__mode_lines_cause,
+              doc: /*  */);
+  Vredisplay__mode_lines_cause
+    = Fmake_vector (make_number (100), make_number (0));
 }
 
 
@@ -29711,12 +30120,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]