Merge from emacs-24; up to 2012-12-06T01:39:03Z!monnier@iro.umontreal.ca
[bpt/emacs.git] / src / xdisp.c
index d0338db..8b0d8b6 100644 (file)
@@ -1,6 +1,7 @@
 /* Display generation from window structure and buffer text.
 
-Copyright (C) 1985-1988, 1993-1995, 1997-2012 Free Software Foundation, Inc.
+Copyright (C) 1985-1988, 1993-1995, 1997-2013 Free Software Foundation,
+Inc.
 
 This file is part of GNU Emacs.
 
@@ -273,9 +274,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <config.h>
 #include <stdio.h>
 #include <limits.h>
-#include <setjmp.h>
 
 #include "lisp.h"
+#include "atimer.h"
 #include "keyboard.h"
 #include "frame.h"
 #include "window.h"
@@ -302,7 +303,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #endif
-#ifdef WINDOWSNT
+#ifdef HAVE_NTGUI
 #include "w32term.h"
 #endif
 #ifdef HAVE_NS
@@ -333,10 +334,10 @@ static Lisp_Object Qinhibit_eval_during_redisplay;
 static Lisp_Object Qbuffer_position, Qposition, Qobject;
 static Lisp_Object Qright_to_left, Qleft_to_right;
 
-/* Cursor shapes */
+/* Cursor shapes */
 Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
 
-/* Pointer shapes */
+/* Pointer shapes */
 static Lisp_Object Qarrow, Qhand;
 Lisp_Object Qtext;
 
@@ -347,6 +348,7 @@ static Lisp_Object Qfontification_functions;
 
 static Lisp_Object Qwrap_prefix;
 static Lisp_Object Qline_prefix;
+static Lisp_Object Qredisplay_internal;
 
 /* Non-nil means don't actually do any redisplay.  */
 
@@ -365,6 +367,28 @@ Lisp_Object Qcenter;
 static Lisp_Object Qmargin, Qpointer;
 static Lisp_Object Qline_height;
 
+/* These setters are used only in this file, so they can be private.  */
+static void
+wset_base_line_number (struct window *w, Lisp_Object val)
+{
+  w->base_line_number = val;
+}
+static void
+wset_base_line_pos (struct window *w, Lisp_Object val)
+{
+  w->base_line_pos = val;
+}
+static void
+wset_column_number_displayed (struct window *w, Lisp_Object val)
+{
+  w->column_number_displayed = val;
+}
+static void
+wset_region_showing (struct window *w, Lisp_Object val)
+{
+  w->region_showing = val;
+}
+
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Test if overflow newline into fringe.  Called with iterator IT
@@ -492,12 +516,6 @@ Lisp_Object Qmenu_bar_update_hook;
 
 static int overlay_arrow_seen;
 
-/* Number of windows showing the buffer of the selected window (or
-   another buffer with the same base buffer).  keyboard.c refers to
-   this.  */
-
-int buffer_shared;
-
 /* Vector containing glyphs for an ellipsis `...'.  */
 
 static Lisp_Object default_invis_vector[3];
@@ -746,9 +764,9 @@ static int clear_image_cache_count;
 static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
 #endif
 
-/* Non-zero while redisplay_internal is in progress.  */
+/* True while redisplay_internal is in progress.  */
 
-int redisplaying_p;
+bool redisplaying_p;
 
 static Lisp_Object Qinhibit_free_realized_faces;
 static Lisp_Object Qmode_line_default_help_echo;
@@ -838,7 +856,6 @@ static int string_char_and_length (const unsigned char *, int *);
 static struct text_pos display_prop_end (struct it *, Lisp_Object,
                                          struct text_pos);
 static int compute_window_start_on_continuation_line (struct window *);
-static Lisp_Object safe_eval_handler (Lisp_Object);
 static void insert_left_trunc_glyphs (struct it *);
 static struct glyph_row *get_overlay_arrow_glyph_row (struct window *,
                                                       Lisp_Object);
@@ -853,7 +870,6 @@ static void push_it (struct it *, struct text_pos *);
 static void iterate_out_of_display_property (struct it *);
 static void pop_it (struct it *);
 static void sync_frame_with_window_matrix_rows (struct window *);
-static void select_frame_for_redisplay (Lisp_Object);
 static void redisplay_internal (void);
 static int echo_area_display (int);
 static void redisplay_windows (Lisp_Object);
@@ -906,6 +922,7 @@ static enum move_it_result
        move_it_in_display_line_to (struct it *, ptrdiff_t, int,
                                   enum move_operation_enum);
 void move_it_vertically_backward (struct it *, int);
+static void get_visually_first_element (struct it *);
 static void init_to_row_start (struct it *, struct window *,
                                struct glyph_row *);
 static int init_to_row_end (struct it *, struct window *,
@@ -984,7 +1001,7 @@ window_text_bottom_y (struct window *w)
 int
 window_box_width (struct window *w, int area)
 {
-  int cols = XFASTINT (WGET (w, total_cols));
+  int cols = XFASTINT (w->total_cols);
   int pixels = 0;
 
   if (!w->pseudo_window_p)
@@ -993,22 +1010,22 @@ window_box_width (struct window *w, int area)
 
       if (area == TEXT_AREA)
        {
-         if (INTEGERP (WGET (w, left_margin_cols)))
-           cols -= XFASTINT (WGET (w, left_margin_cols));
-         if (INTEGERP (WGET (w, right_margin_cols)))
-           cols -= XFASTINT (WGET (w, right_margin_cols));
+         if (INTEGERP (w->left_margin_cols))
+           cols -= XFASTINT (w->left_margin_cols);
+         if (INTEGERP (w->right_margin_cols))
+           cols -= XFASTINT (w->right_margin_cols);
          pixels = -WINDOW_TOTAL_FRINGE_WIDTH (w);
        }
       else if (area == LEFT_MARGIN_AREA)
        {
-         cols = (INTEGERP (WGET (w, left_margin_cols))
-                  ? XFASTINT (WGET (w, left_margin_cols)) : 0);
+         cols = (INTEGERP (w->left_margin_cols)
+                  ? XFASTINT (w->left_margin_cols) : 0);
          pixels = 0;
        }
       else if (area == RIGHT_MARGIN_AREA)
        {
-         cols = (INTEGERP (WGET (w, right_margin_cols))
-                  ? XFASTINT (WGET (w, right_margin_cols)) : 0);
+         cols = (INTEGERP (w->right_margin_cols)
+                  ? XFASTINT (w->right_margin_cols) : 0);
          pixels = 0;
        }
     }
@@ -1023,7 +1040,7 @@ window_box_width (struct window *w, int area)
 int
 window_box_height (struct window *w)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int height = WINDOW_TOTAL_HEIGHT (w);
 
   eassert (height >= 0);
@@ -1112,7 +1129,7 @@ window_box_right_offset (struct window *w, int area)
 int
 window_box_left (struct window *w, int area)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int x;
 
   if (w->pseudo_window_p)
@@ -1169,7 +1186,7 @@ window_box (struct window *w, int area, int *box_x, int *box_y,
    *BOTTOM_RIGHT_Y the coordinates of the bottom-right corner of the
    box.  */
 
-static inline void
+static void
 window_box_edges (struct window *w, int area, int *top_left_x, int *top_left_y,
                   int *bottom_right_x, int *bottom_right_y)
 {
@@ -1256,7 +1273,7 @@ string_from_display_spec (Lisp_Object spec)
 /* Limit insanely large values of W->hscroll on frame F to the largest
    value that will still prevent first_visible_x and last_visible_x of
    'struct it' from overflowing an int.  */
-static inline int
+static int
 window_hscroll_limited (struct window *w, struct frame *f)
 {
   ptrdiff_t window_hscroll = w->hscroll;
@@ -1288,13 +1305,13 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
   if (FRAME_INITIAL_P (XFRAME (WINDOW_FRAME (w))))
     return visible_p;
 
-  if (XBUFFER (WGET (w, buffer)) != current_buffer)
+  if (XBUFFER (w->buffer) != current_buffer)
     {
       old_buffer = current_buffer;
-      set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+      set_buffer_internal_1 (XBUFFER (w->buffer));
     }
 
-  SET_TEXT_POS_FROM_MARKER (top, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (top, w->start);
   /* Scrolling a minibuffer window via scroll bar when the echo area
      shows long text sometimes resets the minibuffer contents behind
      our backs.  */
@@ -1313,7 +1330,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
                           BVAR (current_buffer, header_line_format));
 
   start_display (&it, w, top);
-  move_it_to (&it, charpos, -1, it.last_visible_y-1, -1,
+  move_it_to (&it, charpos, -1, it.last_visible_y - 1, -1,
              (charpos >= 0 ? MOVE_TO_POS : 0) | MOVE_TO_Y);
 
   if (charpos >= 0
@@ -1321,7 +1338,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
           && IT_CHARPOS (it) >= charpos)
          /* When scanning backwards under bidi iteration, move_it_to
             stops at or _before_ CHARPOS, because it stops at or to
-            the _right_ of the character at CHARPOS. */
+            the _right_ of the character at CHARPOS.  */
          || (it.bidi_p && it.bidi_it.scan_dir == -1
              && IT_CHARPOS (it) <= charpos)))
     {
@@ -1603,7 +1620,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
    returns an invalid character.  If we find one, we return a `?', but
    with the length of the invalid character.  */
 
-static inline int
+static int
 string_char_and_length (const unsigned char *str, int *len)
 {
   int c;
@@ -1651,7 +1668,7 @@ string_pos_nchars_ahead (struct text_pos pos, Lisp_Object string, ptrdiff_t ncha
 /* Value is the text position, i.e. character and byte position,
    for character position CHARPOS in STRING.  */
 
-static inline struct text_pos
+static struct text_pos
 string_pos (ptrdiff_t charpos, Lisp_Object string)
 {
   struct text_pos pos;
@@ -1913,7 +1930,7 @@ frame_to_window_pixel_xy (struct window *w, int *x, int *y)
     {
       /* A pseudo-window is always full-width, and starts at the
         left edge of the frame, plus a frame border.  */
-      struct frame *f = XFRAME (WGET (w, frame));
+      struct frame *f = XFRAME (w->frame);
       *x -= FRAME_INTERNAL_BORDER_WIDTH (f);
       *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
     }
@@ -2397,9 +2414,10 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
 /* Error handler for safe_eval and safe_call.  */
 
 static Lisp_Object
-safe_eval_handler (Lisp_Object arg)
+safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args)
 {
-  add_to_log ("Error during redisplay: %S", arg, Qnil);
+  add_to_log ("Error during redisplay: %S signaled %S",
+             Flist (nargs, args), arg);
   return Qnil;
 }
 
@@ -2522,11 +2540,11 @@ static void
 check_window_end (struct window *w)
 {
   if (!MINI_WINDOW_P (w)
-      && !NILP (WGET (w, window_end_valid)))
+      && !NILP (w->window_end_valid))
     {
       struct glyph_row *row;
       eassert ((row = MATRIX_ROW (w->current_matrix,
-                                 XFASTINT (WGET (w, window_end_vpos))),
+                                 XFASTINT (w->window_end_vpos)),
                !row->enabled_p
                || MATRIX_ROW_DISPLAYS_TEXT_P (row)
                || MATRIX_ROW_VPOS (row, w->current_matrix) == 0));
@@ -2541,8 +2559,24 @@ 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;
+}
 
-\f
 /***********************************************************************
                       Iterator initialization
  ***********************************************************************/
@@ -2571,7 +2605,7 @@ init_iterator (struct it *it, struct window *w,
               ptrdiff_t charpos, ptrdiff_t bytepos,
               struct glyph_row *row, enum face_id base_face_id)
 {
-  int highlight_region_p;
+  ptrdiff_t markpos;
   enum face_id remapped_base_face_id = base_face_id;
 
   /* Some precondition checks.  */
@@ -2592,7 +2626,7 @@ init_iterator (struct it *it, struct window *w,
   /* Perhaps remap BASE_FACE_ID to a user-specified alternative.  */
   if (! NILP (Vface_remapping_alist))
     remapped_base_face_id
-      = lookup_basic_face (XFRAME (WGET (w, frame)), base_face_id);
+      = lookup_basic_face (XFRAME (w->frame), base_face_id);
 
   /* Use one of the mode line rows of W's desired matrix if
      appropriate.  */
@@ -2620,7 +2654,7 @@ init_iterator (struct it *it, struct window *w,
   /* The window in which we iterate over current_buffer:  */
   XSETWINDOW (it->window, w);
   it->w = w;
-  it->f = XFRAME (WGET (w, frame));
+  it->f = XFRAME (w->frame);
 
   it->cmp_it.id = -1;
 
@@ -2674,16 +2708,11 @@ 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));
 
-  /* Non-zero if we should highlight the region.  */
-  highlight_region_p
-    = (!NILP (Vtransient_mark_mode)
-       && !NILP (BVAR (current_buffer, mark_active))
-       && XMARKER (BVAR (current_buffer, mark))->buffer != 0);
-
-  /* Set IT->region_beg_charpos and IT->region_end_charpos to the
-     start and end of a visible region in window IT->w.  Set both to
-     -1 to indicate no region.  */
-  if (highlight_region_p
+  /* 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 (0 <= markpos
       /* Maybe highlight only in selected window.  */
       && (/* Either show region everywhere.  */
          highlight_nonselected_windows
@@ -2695,7 +2724,6 @@ init_iterator (struct it *it, struct window *w,
              && WINDOWP (minibuf_selected_window)
              && w == XWINDOW (minibuf_selected_window))))
     {
-      ptrdiff_t markpos = marker_position (BVAR (current_buffer, mark));
       it->region_beg_charpos = min (PT, markpos);
       it->region_end_charpos = max (PT, markpos);
     }
@@ -2704,13 +2732,13 @@ init_iterator (struct it *it, struct window *w,
 
   /* Get the position at which the redisplay_end_trigger hook should
      be run, if it is to be run at all.  */
-  if (MARKERP (WGET (w, redisplay_end_trigger))
-      && XMARKER (WGET (w, redisplay_end_trigger))->buffer != 0)
+  if (MARKERP (w->redisplay_end_trigger)
+      && XMARKER (w->redisplay_end_trigger)->buffer != 0)
     it->redisplay_end_trigger_charpos
-      = marker_position (WGET (w, redisplay_end_trigger));
-  else if (INTEGERP (WGET (w, redisplay_end_trigger)))
+      = marker_position (w->redisplay_end_trigger);
+  else if (INTEGERP (w->redisplay_end_trigger))
     it->redisplay_end_trigger_charpos =
-      clip_to_bounds (PTRDIFF_MIN, XINT (WGET (w, redisplay_end_trigger)), PTRDIFF_MAX);
+      clip_to_bounds (PTRDIFF_MIN, XINT (w->redisplay_end_trigger), PTRDIFF_MAX);
 
   it->tab_width = SANE_TAB_WIDTH (current_buffer);
 
@@ -3090,6 +3118,40 @@ init_from_display_pos (struct it *it, struct window *w, struct display_pos *pos)
       eassert (STRINGP (it->string));
       it->current.string_pos = pos->string_pos;
       it->method = GET_FROM_STRING;
+      it->end_charpos = SCHARS (it->string);
+      /* Set up the bidi iterator for this overlay string.  */
+      if (it->bidi_p)
+       {
+         it->bidi_it.string.lstring = it->string;
+         it->bidi_it.string.s = NULL;
+         it->bidi_it.string.schars = SCHARS (it->string);
+         it->bidi_it.string.bufpos = it->overlay_strings_charpos;
+         it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
+         it->bidi_it.string.unibyte = !it->multibyte_p;
+         bidi_init_it (IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it),
+                       FRAME_WINDOW_P (it->f), &it->bidi_it);
+
+         /* Synchronize the state of the bidi iterator with
+            pos->string_pos.  For any string position other than
+            zero, this will be done automagically when we resume
+            iteration over the string and get_visually_first_element
+            is called.  But if string_pos is zero, and the string is
+            to be reordered for display, we need to resync manually,
+            since it could be that the iteration state recorded in
+            pos ended at string_pos of 0 moving backwards in string.  */
+         if (CHARPOS (pos->string_pos) == 0)
+           {
+             get_visually_first_element (it);
+             if (IT_STRING_CHARPOS (*it) != 0)
+               do {
+                 /* Paranoia.  */
+                 eassert (it->bidi_it.charpos < it->bidi_it.string.schars);
+                 bidi_move_to_visually_next (&it->bidi_it);
+               } while (it->bidi_it.charpos != 0);
+           }
+         eassert (IT_STRING_CHARPOS (*it) == it->bidi_it.charpos
+                  && IT_STRING_BYTEPOS (*it) == it->bidi_it.bytepos);
+       }
     }
 
   if (CHARPOS (pos->string_pos) >= 0)
@@ -3099,6 +3161,9 @@ init_from_display_pos (struct it *it, struct window *w, struct display_pos *pos)
         IT should already be filled with that string.  */
       it->current.string_pos = pos->string_pos;
       eassert (STRINGP (it->string));
+      if (it->bidi_p)
+       bidi_init_it (IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it),
+                     FRAME_WINDOW_P (it->f), &it->bidi_it);
     }
 
   /* Restore position in display vector translations, control
@@ -3321,7 +3386,7 @@ compute_stop_pos (struct it *it)
      interval if there isn't such an interval.  */
   position = make_number (charpos);
   iv = validate_interval_range (object, &position, &position, 0);
-  if (!NULL_INTERVAL_P (iv))
+  if (iv)
     {
       Lisp_Object values_here[LAST_PROP_IDX];
       struct props *p;
@@ -3333,7 +3398,7 @@ compute_stop_pos (struct it *it)
       /* Look for an interval following iv that has different
         properties.  */
       for (next_iv = next_interval (iv);
-          (!NULL_INTERVAL_P (next_iv)
+          (next_iv
            && (NILP (limit)
                || XFASTINT (limit) > next_iv->position));
           next_iv = next_interval (next_iv))
@@ -3351,7 +3416,7 @@ compute_stop_pos (struct it *it)
            break;
        }
 
-      if (!NULL_INTERVAL_P (next_iv))
+      if (next_iv)
        {
          if (INTEGERP (limit)
              && next_iv->position >= XFASTINT (limit))
@@ -3644,7 +3709,7 @@ handle_fontified_prop (struct it *it)
        }
       /* There isn't much we can reasonably do to protect against
         misbehaving fontification, but here's a fig leaf.  */
-      else if (!NILP (BVAR (obuf, name)))
+      else if (BUFFER_LIVE_P (obuf))
        set_buffer_internal_1 (obuf);
 
       /* The fontification code may have added/removed text.
@@ -3700,18 +3765,26 @@ handle_face_prop (struct it *it)
       if (new_face_id != it->face_id)
        {
          struct face *new_face = FACE_FROM_ID (it->f, new_face_id);
+         /* If it->face_id is -1, old_face below will be NULL, see
+            the definition of FACE_FROM_ID.  This will happen if this
+            is the initial call that gets the face.  */
+         struct face *old_face = FACE_FROM_ID (it->f, it->face_id);
 
-         /* If new face has a box but old face has not, this is
-            the start of a run of characters with box, i.e. it has
-            a shadow on the left side.  The value of face_id of the
-            iterator will be -1 if this is the initial call that gets
-            the face.  In this case, we have to look in front of IT's
-            position and see whether there is a face != new_face_id.  */
-         it->start_of_box_run_p
-           = (new_face->box != FACE_NO_BOX
-              && (it->face_id >= 0
-                  || IT_CHARPOS (*it) == BEG
-                  || new_face_id != face_before_it_pos (it)));
+         /* If the value of face_id of the iterator is -1, we have to
+            look in front of IT's position and see whether there is a
+            face there that's different from new_face_id.  */
+         if (!old_face && IT_CHARPOS (*it) > BEG)
+           {
+             int prev_face_id = face_before_it_pos (it);
+
+             old_face = FACE_FROM_ID (it->f, prev_face_id);
+           }
+
+         /* If the new face has a box, but the old face does not,
+            this is the start of a run of characters with box face,
+            i.e. this character has a shadow on the left side.  */
+         it->start_of_box_run_p = (new_face->box != FACE_NO_BOX
+                                   && (old_face == NULL || !old_face->box));
          it->face_box_p = new_face->box != FACE_NO_BOX;
        }
     }
@@ -4047,38 +4120,54 @@ static enum prop_handled
 handle_invisible_prop (struct it *it)
 {
   enum prop_handled handled = HANDLED_NORMALLY;
+  int invis_p;
+  Lisp_Object prop;
 
   if (STRINGP (it->string))
     {
-      Lisp_Object prop, end_charpos, limit, charpos;
+      Lisp_Object end_charpos, limit, charpos;
 
       /* Get the value of the invisible text property at the
         current position.  Value will be nil if there is no such
         property.  */
       charpos = make_number (IT_STRING_CHARPOS (*it));
       prop = Fget_text_property (charpos, Qinvisible, it->string);
+      invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
 
-      if (!NILP (prop)
-         && IT_STRING_CHARPOS (*it) < it->end_charpos)
+      if (invis_p && IT_STRING_CHARPOS (*it) < it->end_charpos)
        {
-         ptrdiff_t endpos;
+         /* Record whether we have to display an ellipsis for the
+            invisible text.  */
+         int display_ellipsis_p = (invis_p == 2);
+         ptrdiff_t len, endpos;
 
          handled = HANDLED_RECOMPUTE_PROPS;
 
-         /* Get the position at which the next change of the
-            invisible text property can be found in IT->string.
-            Value will be nil if the property value is the same for
-            all the rest of IT->string.  */
-         XSETINT (limit, SCHARS (it->string));
-         end_charpos = Fnext_single_property_change (charpos, Qinvisible,
-                                                     it->string, limit);
-
-         /* Text at current position is invisible.  The next
-            change in the property is at position end_charpos.
-            Move IT's current position to that position.  */
-         if (INTEGERP (end_charpos)
-             && (endpos = XFASTINT (end_charpos)) < XFASTINT (limit))
+         /* Get the position at which the next visible text can be
+            found in IT->string, if any.  */
+         endpos = len = SCHARS (it->string);
+         XSETINT (limit, len);
+         do
            {
+             end_charpos = Fnext_single_property_change (charpos, Qinvisible,
+                                                         it->string, limit);
+             if (INTEGERP (end_charpos))
+               {
+                 endpos = XFASTINT (end_charpos);
+                 prop = Fget_text_property (end_charpos, Qinvisible, it->string);
+                 invis_p = TEXT_PROP_MEANS_INVISIBLE (prop);
+                 if (invis_p == 2)
+                   display_ellipsis_p = 1;
+               }
+           }
+         while (invis_p && endpos < len);
+
+         if (display_ellipsis_p)
+           it->ellipsis_p = 1;
+
+         if (endpos < len)
+           {
+             /* Text at END_CHARPOS is visible.  Move IT there.  */
              struct text_pos old;
              ptrdiff_t oldpos;
 
@@ -4114,7 +4203,8 @@ handle_invisible_prop (struct it *it)
              /* The rest of the string is invisible.  If this is an
                 overlay string, proceed with the next overlay string
                 or whatever comes and return a character from there.  */
-             if (it->current.overlay_string_index >= 0)
+             if (it->current.overlay_string_index >= 0
+                 && !display_ellipsis_p)
                {
                  next_overlay_string (it);
                  /* Don't check for overlay strings when we just
@@ -4131,9 +4221,8 @@ handle_invisible_prop (struct it *it)
     }
   else
     {
-      int invis_p;
       ptrdiff_t newpos, next_stop, start_charpos, tem;
-      Lisp_Object pos, prop, overlay;
+      Lisp_Object pos, overlay;
 
       /* First of all, is there invisible text at this position?  */
       tem = start_charpos = IT_CHARPOS (*it);
@@ -4408,7 +4497,7 @@ handle_display_prop (struct it *it)
      if it was a text property.  */
 
   if (!STRINGP (it->string))
-    object = WGET (it->w, buffer);
+    object = it->w->buffer;
 
   display_replaced_p = handle_display_spec (it, propval, object, overlay,
                                            position, bufpos,
@@ -4816,7 +4905,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->what = IT_IMAGE;
          it->image_id = -1; /* no image */
          it->position = start_pos;
-         it->object = NILP (object) ? WGET (it->w, buffer) : object;
+         it->object = NILP (object) ? it->w->buffer : object;
          it->method = GET_FROM_IMAGE;
          it->from_overlay = Qnil;
          it->face_id = face_id;
@@ -4962,7 +5051,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->what = IT_IMAGE;
          it->image_id = lookup_image (it->f, value);
          it->position = start_pos;
-         it->object = NILP (object) ? WGET (it->w, buffer) : object;
+         it->object = NILP (object) ? it->w->buffer : object;
          it->method = GET_FROM_IMAGE;
 
          /* Say that we haven't consumed the characters with
@@ -5309,6 +5398,7 @@ next_overlay_string (struct it *it)
       SET_TEXT_POS (it->current.string_pos, 0, 0);
       it->method = GET_FROM_STRING;
       it->stop_charpos = 0;
+      it->end_charpos = SCHARS (it->string);
       if (it->cmp_it.stop_pos >= 0)
        it->cmp_it.stop_pos = 0;
       it->prev_stop = 0;
@@ -5785,7 +5875,7 @@ pop_it (struct it *it)
       it->object = p->u.stretch.object;
       break;
     case GET_FROM_BUFFER:
-      it->object = WGET (it->w, buffer);
+      it->object = it->w->buffer;
       break;
     case GET_FROM_STRING:
       it->object = it->string;
@@ -5798,7 +5888,7 @@ pop_it (struct it *it)
       else
        {
          it->method = GET_FROM_BUFFER;
-         it->object = WGET (it->w, buffer);
+         it->object = it->w->buffer;
        }
     }
   it->end_charpos = p->end_charpos;
@@ -6010,7 +6100,7 @@ back_to_previous_visible_line_start (struct it *it)
       {
        Lisp_Object prop;
        prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
-                                    Qinvisible, it->window);
+                                  Qinvisible, it->window);
        if (TEXT_PROP_MEANS_INVISIBLE (prop))
          continue;
       }
@@ -6236,7 +6326,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
   IT_STRING_BYTEPOS (*it) = -1;
   it->string = Qnil;
   it->method = GET_FROM_BUFFER;
-  it->object = WGET (it->w, buffer);
+  it->object = it->w->buffer;
   it->area = TEXT_AREA;
   it->multibyte_p = !NILP (BVAR (current_buffer, enable_multibyte_characters));
   it->sp = 0;
@@ -6262,6 +6352,8 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
       it->stop_charpos = CHARPOS (pos);
       it->base_level_stop = CHARPOS (pos);
     }
+  /* This make the information stored in it->cmp_it invalidate.  */
+  it->cmp_it.id = -1;
 }
 
 
@@ -7085,7 +7177,7 @@ set_iterator_to_next (struct it *it, int reseat_p)
          else
            {
              it->method = GET_FROM_BUFFER;
-             it->object = WGET (it->w, buffer);
+             it->object = it->w->buffer;
            }
 
          it->dpvec = NULL;
@@ -7268,7 +7360,7 @@ set_iterator_to_next (struct it *it, int reseat_p)
 
     default:
       /* There are no other methods defined, so this should be a bug.  */
-      abort ();
+      emacs_abort ();
     }
 
   eassert (it->method != GET_FROM_STRING
@@ -7660,7 +7752,7 @@ next_element_from_ellipsis (struct it *it)
         setting face_before_selective_p.  */
       it->saved_face_id = it->face_id;
       it->method = GET_FROM_BUFFER;
-      it->object = WGET (it->w, buffer);
+      it->object = it->w->buffer;
       reseat_at_next_visible_line_start (it, 1);
       it->face_before_selective_p = 1;
     }
@@ -7718,12 +7810,12 @@ compute_stop_pos_backwards (struct it *it)
     {
       it->end_charpos = min (charpos + 1, ZV);
       charpos = max (charpos - SCAN_BACK_LIMIT, BEGV);
-      SET_TEXT_POS (pos, charpos, BYTE_TO_CHAR (charpos));
+      SET_TEXT_POS (pos, charpos, CHAR_TO_BYTE (charpos));
       reseat_1 (it, pos, 0);
       compute_stop_pos (it);
       /* We must advance forward, right?  */
       if (it->stop_charpos <= charpos)
-       abort ();
+       emacs_abort ();
     }
   while (charpos > BEGV && it->stop_charpos >= it->end_charpos);
 
@@ -7772,7 +7864,7 @@ handle_stop_backwards (struct it *it, ptrdiff_t charpos)
       compute_stop_pos (it);
       /* We must advance forward, right?  */
       if (it->stop_charpos <= it->prev_stop)
-       abort ();
+       emacs_abort ();
       charpos = it->stop_charpos;
     }
   while (charpos <= where_we_are);
@@ -7924,7 +8016,7 @@ next_element_from_buffer (struct it *it)
 
       /* Record what we have and where it came from.  */
       it->what = IT_CHARACTER;
-      it->object = WGET (it->w, buffer);
+      it->object = it->w->buffer;
       it->position = it->current.pos;
 
       /* Normally we return the character found above, except when we
@@ -7981,7 +8073,7 @@ run_redisplay_end_trigger_hook (struct it *it)
 
   /* Since we are *trying* to run these functions, don't try to run
      them again, even if they get an error.  */
-  WSET (it->w, redisplay_end_trigger, Qnil);
+  wset_redisplay_end_trigger (it->w, Qnil);
   Frun_hook_with_args (3, args);
 
   /* Notice if it changed the face of the character we are on.  */
@@ -8030,7 +8122,7 @@ next_element_from_composition (struct it *it)
          return 0;
        }
       it->position = it->current.pos;
-      it->object = WGET (it->w, buffer);
+      it->object = it->w->buffer;
       it->c = composition_update_it (&it->cmp_it, IT_CHARPOS (*it),
                                     IT_BYTEPOS (*it), Qnil);
     }
@@ -8860,7 +8952,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
          break;
 
        default:
-         abort ();
+         emacs_abort ();
        }
 
       /* Reset/increment for the next run.  */
@@ -8891,7 +8983,7 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos
       && it->current_x == it->last_visible_x - 1
       && it->c != '\n'
       && it->c != '\t'
-      && it->vpos < XFASTINT (WGET (it->w, window_end_vpos)))
+      && it->vpos < XFASTINT (it->w->window_end_vpos))
     {
       it->continuation_lines_width += it->current_x;
       it->current_x = it->hpos = it->max_ascent = it->max_descent = 0;
@@ -9253,12 +9345,6 @@ add_to_log (const char *format, Lisp_Object arg1, Lisp_Object arg2)
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   USE_SAFE_ALLOCA;
 
-  /* Do nothing if called asynchronously.  Inserting text into
-     a buffer may call after-change-functions and alike and
-     that would means running Lisp asynchronously.  */
-  if (handling_signal)
-    return;
-
   fmt = msg = Qnil;
   GCPRO4 (fmt, msg, arg1, arg2);
 
@@ -9312,13 +9398,14 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
       int old_windows_or_buffers_changed = windows_or_buffers_changed;
       ptrdiff_t point_at_end = 0;
       ptrdiff_t zv_at_end = 0;
-      Lisp_Object old_deactivate_mark, tem;
+      Lisp_Object old_deactivate_mark;
+      bool shown;
       struct gcpro gcpro1;
 
       old_deactivate_mark = Vdeactivate_mark;
       oldbuf = current_buffer;
       Fset_buffer (Fget_buffer_create (Vmessages_buffer_name));
-      BVAR (current_buffer, undo_list) = Qt;
+      bset_undo_list (current_buffer, Qt);
 
       oldpoint = message_dolog_marker1;
       set_marker_restricted (oldpoint, make_number (PT), Qnil);
@@ -9427,7 +9514,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
              del_range_both (BEG, BEG_BYTE, PT, PT_BYTE, 0);
            }
        }
-      BEGV = XMARKER (oldbegv)->charpos;
+      BEGV = marker_position (oldbegv);
       BEGV_BYTE = marker_byte_position (oldbegv);
 
       if (zv_at_end)
@@ -9437,7 +9524,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
        }
       else
        {
-         ZV = XMARKER (oldzv)->charpos;
+         ZV = marker_position (oldzv);
          ZV_BYTE = marker_byte_position (oldzv);
        }
 
@@ -9446,17 +9533,17 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
       else
        /* We can't do Fgoto_char (oldpoint) because it will run some
            Lisp code.  */
-       TEMP_SET_PT_BOTH (XMARKER (oldpoint)->charpos,
-                         XMARKER (oldpoint)->bytepos);
+       TEMP_SET_PT_BOTH (marker_position (oldpoint),
+                         marker_byte_position (oldpoint));
 
       UNGCPRO;
       unchain_marker (XMARKER (oldpoint));
       unchain_marker (XMARKER (oldbegv));
       unchain_marker (XMARKER (oldzv));
 
-      tem = Fget_buffer_window (Fcurrent_buffer (), Qt);
+      shown = buffer_window_count (current_buffer) > 0;
       set_buffer_internal (oldbuf);
-      if (NILP (tem))
+      if (!shown)
        windows_or_buffers_changed = old_windows_or_buffers_changed;
       message_log_need_newline = !nlflag;
       Vdeactivate_mark = old_deactivate_mark;
@@ -9569,7 +9656,7 @@ message2_nolog (const char *m, ptrdiff_t nbytes, int multibyte)
       do_pending_window_change (0);
       echo_area_display (1);
       do_pending_window_change (0);
-      if (FRAME_TERMINAL (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+      if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
        (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
     }
 }
@@ -9643,7 +9730,7 @@ message3_nolog (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
       /* Get the frame containing the mini-buffer
         that the selected frame is using.  */
       mini_window = FRAME_MINIBUF_WINDOW (sf);
-      frame = WGET (XWINDOW (mini_window), frame);
+      frame = XWINDOW (mini_window)->frame;
       f = XFRAME (frame);
 
       FRAME_SAMPLE_VISIBILITY (f);
@@ -9666,7 +9753,7 @@ message3_nolog (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
       do_pending_window_change (0);
       echo_area_display (1);
       do_pending_window_change (0);
-      if (FRAME_TERMINAL (f)->frame_up_to_date_hook != 0 && ! gc_in_progress)
+      if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
        (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
     }
 }
@@ -9871,7 +9958,7 @@ ensure_echo_area_buffers (void)
 
   for (i = 0; i < 2; ++i)
     if (!BUFFERP (echo_buffer[i])
-       || NILP (BVAR (XBUFFER (echo_buffer[i]), name)))
+       || !BUFFER_LIVE_P (XBUFFER (echo_buffer[i])))
       {
        char name[30];
        Lisp_Object old_buffer;
@@ -9880,7 +9967,7 @@ ensure_echo_area_buffers (void)
        old_buffer = echo_buffer[i];
        echo_buffer[i] = Fget_buffer_create
          (make_formatted_string (name, " *Echo Area %d*", i));
-       BVAR (XBUFFER (echo_buffer[i]), truncate_lines) = Qnil;
+       bset_truncate_lines (XBUFFER (echo_buffer[i]), Qnil);
        /* to force word wrap in echo area -
           it was decided to postpone this*/
        /* XBUFFER (echo_buffer[i])->word_wrap = Qt; */
@@ -9969,12 +10056,12 @@ with_echo_area_buffer (struct window *w, int which,
   set_buffer_internal_1 (XBUFFER (buffer));
   if (w)
     {
-      WSET (w, buffer, buffer);
-      set_marker_both (WGET (w, pointm), buffer, BEG, BEG_BYTE);
+      wset_buffer (w, buffer);
+      set_marker_both (w->pointm, buffer, BEG, BEG_BYTE);
     }
 
-  BVAR (current_buffer, undo_list) = Qt;
-  BVAR (current_buffer, read_only) = Qnil;
+  bset_undo_list (current_buffer, Qt);
+  bset_read_only (current_buffer, Qnil);
   specbind (Qinhibit_read_only, Qt);
   specbind (Qinhibit_modification_hooks, Qt);
 
@@ -10018,9 +10105,9 @@ with_echo_area_buffer_unwind_data (struct window *w)
   if (w)
     {
       XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i;
-      ASET (vector, i, WGET (w, buffer)); ++i;
-      ASET (vector, i, make_number (XMARKER (WGET (w, pointm))->charpos)); ++i;
-      ASET (vector, i, make_number (XMARKER (WGET (w, pointm))->bytepos)); ++i;
+      ASET (vector, i, w->buffer); ++i;
+      ASET (vector, i, make_number (marker_position (w->pointm))); ++i;
+      ASET (vector, i, make_number (marker_byte_position (w->pointm))); ++i;
     }
   else
     {
@@ -10054,8 +10141,8 @@ unwind_with_echo_area_buffer (Lisp_Object vector)
       charpos = AREF (vector, 5);
       bytepos = AREF (vector, 6);
 
-      WSET (w, buffer, buffer);
-      set_marker_both (WGET (w, pointm), buffer,
+      wset_buffer (w, buffer);
+      set_marker_both (w->pointm, buffer,
                       XFASTINT (charpos), XFASTINT (bytepos));
     }
 
@@ -10087,7 +10174,7 @@ setup_echo_area_for_printing (int multibyte_p)
 
       /* Switch to that buffer and clear it.  */
       set_buffer_internal (XBUFFER (echo_area_buffer[0]));
-      BVAR (current_buffer, truncate_lines) = Qnil;
+      bset_truncate_lines (current_buffer, Qnil);
 
       if (Z > BEG)
        {
@@ -10130,7 +10217,7 @@ setup_echo_area_for_printing (int multibyte_p)
        {
          /* Someone switched buffers between print requests.  */
          set_buffer_internal (XBUFFER (echo_area_buffer[0]));
-         BVAR (current_buffer, truncate_lines) = Qnil;
+         bset_truncate_lines (current_buffer, Qnil);
        }
     }
 }
@@ -10194,7 +10281,7 @@ display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
   window_height_changed_p = resize_mini_window (w, 0);
 
   /* Use the starting position chosen by resize_mini_window.  */
-  SET_TEXT_POS_FROM_MARKER (start, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (start, w->start);
 
   /* Display.  */
   clear_glyph_matrix (w->desired_matrix);
@@ -10265,15 +10352,15 @@ resize_mini_window_1 (ptrdiff_t a1, Lisp_Object exactly, ptrdiff_t a3, ptrdiff_t
 int
 resize_mini_window (struct window *w, int exact_p)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int window_height_changed_p = 0;
 
   eassert (MINI_WINDOW_P (w));
 
   /* By default, start display at the beginning.  */
-  set_marker_both (WGET (w, start), WGET (w, buffer),
-                  BUF_BEGV (XBUFFER (WGET (w, buffer))),
-                  BUF_BEGV_BYTE (XBUFFER (WGET (w, buffer))));
+  set_marker_both (w->start, w->buffer,
+                  BUF_BEGV (XBUFFER (w->buffer)),
+                  BUF_BEGV_BYTE (XBUFFER (w->buffer)));
 
   /* Don't resize windows while redisplaying a window; it would
      confuse redisplay functions when the size of the window they are
@@ -10300,10 +10387,10 @@ resize_mini_window (struct window *w, int exact_p)
       struct text_pos start;
       struct buffer *old_current_buffer = NULL;
 
-      if (current_buffer != XBUFFER (WGET (w, buffer)))
+      if (current_buffer != XBUFFER (w->buffer))
        {
          old_current_buffer = current_buffer;
-         set_buffer_internal (XBUFFER (WGET (w, buffer)));
+         set_buffer_internal (XBUFFER (w->buffer));
        }
 
       init_iterator (&it, w, BEGV, BEGV_BYTE, NULL, DEFAULT_FACE_ID);
@@ -10317,8 +10404,7 @@ resize_mini_window (struct window *w, int exact_p)
        max_height = total_height / 4;
 
       /* Correct that max. height if it's bogus.  */
-      max_height = max (1, max_height);
-      max_height = min (total_height, max_height);
+      max_height = clip_to_bounds (1, max_height, total_height);
 
       /* Find out the height of the text in the window.  */
       if (it.line_wrap == TRUNCATE)
@@ -10345,7 +10431,7 @@ resize_mini_window (struct window *w, int exact_p)
        }
       else
        SET_TEXT_POS (start, BEGV, BEGV_BYTE);
-      SET_MARKER_FROM_TEXT_POS (WGET (w, start), start);
+      SET_MARKER_FROM_TEXT_POS (w->start, start);
 
       if (EQ (Vresize_mini_windows, Qgrow_only))
        {
@@ -10442,11 +10528,10 @@ current_message_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
    empty.  This is a relatively infrequent operation, so it's not
    worth optimizing.  */
 
-int
+bool
 push_message (void)
 {
-  Lisp_Object msg;
-  msg = current_message ();
+  Lisp_Object msg = current_message ();
   Vmessage_stack = Fcons (msg, Vmessage_stack);
   return STRINGP (msg);
 }
@@ -10495,7 +10580,7 @@ void
 check_message_stack (void)
 {
   if (!NILP (Vmessage_stack))
-    abort ();
+    emacs_abort ();
 }
 
 
@@ -10534,7 +10619,6 @@ truncate_message_1 (ptrdiff_t nchars, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4
   return 0;
 }
 
-
 /* Set the current message to a substring of S or STRING.
 
    If STRING is a Lisp string, set the message to the first NBYTES
@@ -10561,6 +10645,10 @@ set_message (const char *s, Lisp_Object string,
                         (intptr_t) s, string, nbytes, multibyte_p);
   message_buf_print = 0;
   help_echo_showing_p = 0;
+
+  if (STRINGP (Vdebug_on_message)
+      && fast_string_match (Vdebug_on_message, string) >= 0)
+    call_debugger (list2 (Qerror, string));
 }
 
 
@@ -10582,9 +10670,9 @@ set_message_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t nbytes, ptrdiff_t multiby
       != !NILP (BVAR (current_buffer, enable_multibyte_characters)))
     Fset_buffer_multibyte (message_enable_multibyte ? Qt : Qnil);
 
-  BVAR (current_buffer, truncate_lines) = message_truncate_lines ? Qt : Qnil;
+  bset_truncate_lines (current_buffer, message_truncate_lines ? Qt : Qnil);
   if (!NILP (BVAR (current_buffer, bidi_display_reordering)))
-    BVAR (current_buffer, bidi_paragraph_direction) = Qleft_to_right;
+    bset_bidi_paragraph_direction (current_buffer, Qleft_to_right);
 
   /* Insert new message at BEG.  */
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
@@ -10693,7 +10781,7 @@ clear_garbaged_frames (void)
            {
              if (f->resized_p)
                {
-                 Fredraw_frame (frame);
+                 redraw_frame (f);
                  f->force_flush_display_p = 1;
                }
              clear_current_matrices (f);
@@ -10740,8 +10828,7 @@ echo_area_display (int update_frame_p)
 #endif /* HAVE_WINDOW_SYSTEM */
 
   /* Redraw garbaged frames.  */
-  if (frame_garbaged)
-    clear_garbaged_frames ();
+  clear_garbaged_frames ();
 
   if (!NILP (echo_area_buffer[0]) || minibuf_level == 0)
     {
@@ -10814,8 +10901,52 @@ 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 doesn't reflect the actual state of current buffer due
+   to its text or overlays change.  FIXME: this may be called when
+   XBUFFER (w->buffer) != current_buffer, which looks suspicious.  */
+
+static int
+window_outdated (struct window *w)
+{
+  return (w->last_modified < MODIFF
+         || w->last_overlay_modified < OVERLAY_MODIFF);
+}
+
+/* Nonzero if W's buffer was changed but not saved or Transient Mark mode
+   is enabled and mark of W's buffer was changed since last W's update.  */
+
+static int
+window_buffer_changed (struct window *w)
+{
+  struct buffer *b = XBUFFER (w->buffer);
+
+  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)))
+             != !NILP (w->region_showing)));
+}
+
+/* Nonzero if W has %c in its mode line and mode line should be updated.  */
+
+static int
+mode_line_update_needed (struct window *w)
+{
+  return (!NILP (w->column_number_displayed)
+         && !(PT == w->last_point && !window_outdated (w))
+         && (XFASTINT (w->column_number_displayed) != current_column ()));
+}
 
-\f
 /***********************************************************************
                     Mode Lines and Frame Titles
  ***********************************************************************/
@@ -10891,7 +11022,7 @@ format_mode_line_unwind_data (struct frame *target_frame,
       /* Similarly to `with-selected-window', if the operation selects
         a window on another frame, we must restore that frame's
         selected window, and (for a tty) the top-frame.  */
-      ASET (vector, 8, FGET (target_frame, selected_window));
+      ASET (vector, 8, target_frame->selected_window);
       if (FRAME_TERMCAP_P (target_frame))
        ASET (vector, 9, FRAME_TTY (target_frame)->top_frame);
     }
@@ -11020,17 +11151,15 @@ x_consider_frame_title (Lisp_Object frame)
       || f->explicit_name)
     {
       /* Do we have more than one visible frame on this X display?  */
-      Lisp_Object tail;
-      Lisp_Object fmt;
+      Lisp_Object tail, other_frame, fmt;
       ptrdiff_t title_start;
       char *title;
       ptrdiff_t len;
       struct it it;
       ptrdiff_t count = SPECPDL_INDEX ();
 
-      for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+      FOR_EACH_FRAME (tail, other_frame)
        {
-         Lisp_Object other_frame = XCAR (tail);
          struct frame *tf = XFRAME (other_frame);
 
          if (tf != f
@@ -11051,14 +11180,14 @@ x_consider_frame_title (Lisp_Object frame)
                             format_mode_line_unwind_data
                               (f, current_buffer, selected_window, 0));
 
-      Fselect_window (FGET (f, selected_window), Qt);
+      Fselect_window (f->selected_window, Qt);
       set_buffer_internal_1
-       (XBUFFER (WGET (XWINDOW (FGET (f, selected_window)), buffer)));
+       (XBUFFER (XWINDOW (f->selected_window)->buffer));
       fmt = FRAME_ICONIFIED_P (f) ? Vicon_title_format : Vframe_title_format;
 
       mode_line_target = MODE_LINE_TITLE;
       title_start = MODE_LINE_NOPROP_LEN (0);
-      init_iterator (&it, XWINDOW (FGET (f, selected_window)), -1, -1,
+      init_iterator (&it, XWINDOW (f->selected_window), -1, -1,
                     NULL, DEFAULT_FACE_ID);
       display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
       len = MODE_LINE_NOPROP_LEN (title_start);
@@ -11070,9 +11199,9 @@ x_consider_frame_title (Lisp_Object frame)
         already wasted too much time by walking through the list with
         display_mode_element, then we might need to optimize at a
         higher level than this.)  */
-      if (! STRINGP (FGET (f, name))
-         || SBYTES (FGET (f, name)) != len
-         || memcmp (title, SDATA (FGET (f, name)), len) != 0)
+      if (! STRINGP (f->name)
+         || SBYTES (f->name) != len
+         || memcmp (title, SDATA (f->name), len) != 0)
        x_implicitly_set_name (f, make_string (title, len), Qnil);
     }
 }
@@ -11123,7 +11252,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 > 1
+                || buffer_shared_and_changed ()
                 || windows_or_buffers_changed);
   if (all_windows)
     {
@@ -11172,8 +11301,7 @@ prepare_menu_bars (void)
           if (windows_or_buffers_changed
              && FRAME_NS_P (f))
             ns_set_doc_edited
-             (f, Fbuffer_modified_p
-              (WGET (XWINDOW (FGET (f, selected_window)), buffer)));
+             (f, Fbuffer_modified_p (XWINDOW (f->selected_window)->buffer));
 #endif
          UNGCPRO;
        }
@@ -11238,19 +11366,14 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
          /* This used to test w->update_mode_line, but we believe
             there is no need to recompute the menu in that case.  */
          || update_mode_lines
-         || ((BUF_SAVE_MODIFF (XBUFFER (WGET (w, buffer)))
-              < BUF_MODIFF (XBUFFER (WGET (w, buffer))))
-             != w->last_had_star)
-         || ((!NILP (Vtransient_mark_mode)
-              && !NILP (BVAR (XBUFFER (WGET (w, buffer)), mark_active)))
-             != !NILP (WGET (w, region_showing))))
+         || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
          ptrdiff_t count = SPECPDL_INDEX ();
 
          specbind (Qinhibit_menubar_update, Qt);
 
-         set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+         set_buffer_internal_1 (XBUFFER (w->buffer));
          if (save_match_data)
            record_unwind_save_match_data ();
          if (NILP (Voverriding_local_map_menu_flag))
@@ -11275,7 +11398,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
            }
 
          XSETFRAME (Vmenu_updating_frame, f);
-         FSET (f, menu_bar_items, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
+         fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f)));
 
          /* Redisplay the menu bar in case we changed it.  */
 #if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) \
@@ -11369,11 +11492,11 @@ x_cursor_to (int vpos, int hpos, int y, int x)
      This will also set the cursor position of W.  */
   if (updated_window == NULL)
     {
-      BLOCK_INPUT;
+      block_input ();
       display_and_set_cursor (w, 1, hpos, vpos, x, y);
       if (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
        FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ());
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -11395,11 +11518,18 @@ FRAME_PTR last_mouse_frame;
 
 int last_tool_bar_item;
 
-
+/* Select `frame' temporarily without running all the code in
+   do_switch_frame.
+   FIXME: Maybe do_switch_frame should be trimmed down similarly
+   when `norecord' is set.  */
 static Lisp_Object
-update_tool_bar_unwind (Lisp_Object frame)
+fast_set_selected_frame (Lisp_Object frame)
 {
-  selected_frame = frame;
+  if (!EQ (selected_frame, frame))
+    {
+      selected_frame = frame;
+      selected_window = XFRAME (frame)->selected_window;
+    }
   return Qnil;
 }
 
@@ -11414,8 +11544,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 (FGET (f, tool_bar_window))
-    && WINDOW_TOTAL_LINES (XWINDOW (FGET (f, tool_bar_window))) > 0;
+  int do_update = WINDOWP (f->tool_bar_window)
+    && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
 #endif
 
   if (do_update)
@@ -11436,12 +11566,7 @@ update_tool_bar (struct frame *f, int save_match_data)
       if (windows_or_buffers_changed
          || w->update_mode_line
          || update_mode_lines
-         || ((BUF_SAVE_MODIFF (XBUFFER (WGET (w, buffer)))
-              < BUF_MODIFF (XBUFFER (WGET (w, buffer))))
-             != w->last_had_star)
-         || ((!NILP (Vtransient_mark_mode)
-              && !NILP (BVAR (XBUFFER (WGET (w, buffer)), mark_active)))
-             != !NILP (WGET (w, region_showing))))
+         || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
          ptrdiff_t count = SPECPDL_INDEX ();
@@ -11452,7 +11577,7 @@ update_tool_bar (struct frame *f, int save_match_data)
          /* Set current_buffer to the buffer of the selected
             window of the frame, so that we get the right local
             keymaps.  */
-         set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+         set_buffer_internal_1 (XBUFFER (w->buffer));
 
          /* Save match data, if we must.  */
          if (save_match_data)
@@ -11471,27 +11596,31 @@ update_tool_bar (struct frame *f, int save_match_data)
             before calling tool_bar_items, because the calculation of
             the tool-bar keymap uses the selected frame (see
             `tool-bar-make-keymap' in tool-bar.el).  */
-         record_unwind_protect (update_tool_bar_unwind, selected_frame);
+         eassert (EQ (selected_window,
+                      /* Since we only explicitly preserve selected_frame,
+                         check that selected_window would be redundant.  */
+                      XFRAME (selected_frame)->selected_window));
+         record_unwind_protect (fast_set_selected_frame, selected_frame);
          XSETFRAME (frame, f);
-         selected_frame = frame;
+         fast_set_selected_frame (frame);
 
          /* Build desired tool-bar items from keymaps.  */
           new_tool_bar
-           = tool_bar_items (Fcopy_sequence (FGET (f, tool_bar_items)),
+           = tool_bar_items (Fcopy_sequence (f->tool_bar_items),
                              &new_n_tool_bar);
 
          /* Redisplay the tool-bar if we changed it.  */
          if (new_n_tool_bar != f->n_tool_bar_items
-             || NILP (Fequal (new_tool_bar, FGET (f, tool_bar_items))))
+             || NILP (Fequal (new_tool_bar, f->tool_bar_items)))
             {
               /* Redisplay that happens asynchronously due to an expose event
                  may access f->tool_bar_items.  Make sure we update both
                  variables within BLOCK_INPUT so no such event interrupts.  */
-              BLOCK_INPUT;
-              FSET (f, tool_bar_items, new_tool_bar);
+              block_input ();
+              fset_tool_bar_items (f, new_tool_bar);
               f->n_tool_bar_items = new_n_tool_bar;
               w->update_mode_line = 1;
-              UNBLOCK_INPUT;
+              unblock_input ();
             }
 
          UNGCPRO;
@@ -11521,22 +11650,22 @@ build_desired_tool_bar_string (struct frame *f)
      Otherwise, make a new string.  */
 
   /* The size of the string we might be able to reuse.  */
-  size = (STRINGP (FGET (f, desired_tool_bar_string))
-         ? SCHARS (FGET (f, desired_tool_bar_string))
+  size = (STRINGP (f->desired_tool_bar_string)
+         ? SCHARS (f->desired_tool_bar_string)
          : 0);
 
   /* We need one space in the string for each image.  */
   size_needed = f->n_tool_bar_items;
 
   /* Reuse f->desired_tool_bar_string, if possible.  */
-  if (size < size_needed || NILP (FGET (f, desired_tool_bar_string)))
-    FSET (f, desired_tool_bar_string,
-         Fmake_string (make_number (size_needed), make_number (' ')));
+  if (size < size_needed || NILP (f->desired_tool_bar_string))
+    fset_desired_tool_bar_string
+      (f, Fmake_string (make_number (size_needed), make_number (' ')));
   else
     {
       props = list4 (Qdisplay, Qnil, Qmenu_item, Qnil);
       Fremove_text_properties (make_number (0), make_number (size),
-                              props, FGET (f, desired_tool_bar_string));
+                              props, f->desired_tool_bar_string);
     }
 
   /* Put a `display' property on the string for the images to display,
@@ -11545,7 +11674,7 @@ build_desired_tool_bar_string (struct frame *f)
   for (i = 0; i < f->n_tool_bar_items; ++i)
     {
 #define PROP(IDX) \
-  AREF (FGET (f, tool_bar_items), i * TOOL_BAR_ITEM_NSLOTS + (IDX))
+  AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
 
       int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
       int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
@@ -11654,11 +11783,11 @@ build_desired_tool_bar_string (struct frame *f)
          string.  The string can be longer than needed when we reuse a
          previous string.  */
       if (i + 1 == f->n_tool_bar_items)
-       end = SCHARS (FGET (f, desired_tool_bar_string));
+       end = SCHARS (f->desired_tool_bar_string);
       else
        end = i + 1;
       Fadd_text_properties (make_number (i), make_number (end),
-                           props, FGET (f, desired_tool_bar_string));
+                           props, f->desired_tool_bar_string);
 #undef PROP
     }
 
@@ -11808,7 +11937,7 @@ display_tool_bar_line (struct it *it, int height)
 static int
 tool_bar_lines_needed (struct frame *f, int *n_rows)
 {
-  struct window *w = XWINDOW (FGET (f, tool_bar_window));
+  struct window *w = XWINDOW (f->tool_bar_window);
   struct it it;
   /* tool_bar_lines_needed is called from redisplay_tool_bar after building
      the desired matrix, so use (unused) mode-line row as temporary row to
@@ -11820,7 +11949,7 @@ tool_bar_lines_needed (struct frame *f, int *n_rows)
   init_iterator (&it, w, -1, -1, temp_row, TOOL_BAR_FACE_ID);
   it.first_visible_x = 0;
   it.last_visible_x = FRAME_TOTAL_COLS (f) * FRAME_COLUMN_WIDTH (f);
-  reseat_to_string (&it, NULL, FGET (f, desired_tool_bar_string), 0, 0, 0, -1);
+  reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
   it.paragraph_embedding = L2R;
 
   while (!ITERATOR_AT_END_P (&it))
@@ -11841,21 +11970,16 @@ tool_bar_lines_needed (struct frame *f, int *n_rows)
 
 DEFUN ("tool-bar-lines-needed", Ftool_bar_lines_needed, Stool_bar_lines_needed,
        0, 1, 0,
-       doc: /* Return the number of lines occupied by the tool bar of FRAME.  */)
+       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)
 {
-  struct frame *f;
+  struct frame *f = decode_any_frame (frame);
   struct window *w;
   int nlines = 0;
 
-  if (NILP (frame))
-    frame = selected_frame;
-  else
-    CHECK_FRAME (frame);
-  f = XFRAME (frame);
-
-  if (WINDOWP (FGET (f, tool_bar_window))
-      && (w = XWINDOW (FGET (f, tool_bar_window)),
+  if (WINDOWP (f->tool_bar_window)
+      && (w = XWINDOW (f->tool_bar_window),
          WINDOW_TOTAL_LINES (w) > 0))
     {
       update_tool_bar (f, 1);
@@ -11890,8 +12014,8 @@ redisplay_tool_bar (struct frame *f)
      do anything.  This means you must start with tool-bar-lines
      non-zero to get the auto-sizing effect.  Or in other words, you
      can turn off tool-bars by specifying tool-bar-lines zero.  */
-  if (!WINDOWP (FGET (f, tool_bar_window))
-      || (w = XWINDOW (FGET (f, tool_bar_window)),
+  if (!WINDOWP (f->tool_bar_window)
+      || (w = XWINDOW (f->tool_bar_window),
           WINDOW_TOTAL_LINES (w) == 0))
     return 0;
 
@@ -11903,7 +12027,7 @@ redisplay_tool_bar (struct frame *f)
 
   /* Build a string that represents the contents of the tool-bar.  */
   build_desired_tool_bar_string (f);
-  reseat_to_string (&it, NULL, FGET (f, desired_tool_bar_string), 0, 0, 0, -1);
+  reseat_to_string (&it, NULL, f->desired_tool_bar_string, 0, 0, 0, -1);
   /* FIXME: This should be controlled by a user option.  But it
      doesn't make sense to have an R2L tool bar if the menu bar cannot
      be drawn also R2L, and making the menu bar R2L is tricky due
@@ -12060,14 +12184,14 @@ tool_bar_item_info (struct frame *f, struct glyph *glyph, int *prop_idx)
   /* This function can be called asynchronously, which means we must
      exclude any possibility that Fget_text_property signals an
      error.  */
-  charpos = min (SCHARS (FGET (f, current_tool_bar_string)), glyph->charpos);
+  charpos = min (SCHARS (f->current_tool_bar_string), glyph->charpos);
   charpos = max (0, charpos);
 
   /* Get the text property `menu-item' at pos. The value of that
      property is the start index of this item's properties in
      F->tool_bar_items.  */
   prop = Fget_text_property (make_number (charpos),
-                            Qmenu_item, FGET (f, current_tool_bar_string));
+                            Qmenu_item, f->current_tool_bar_string);
   if (INTEGERP (prop))
     {
       *prop_idx = XINT (prop);
@@ -12095,7 +12219,7 @@ get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
                   int *hpos, int *vpos, int *prop_idx)
 {
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
-  struct window *w = XWINDOW (FGET (f, tool_bar_window));
+  struct window *w = XWINDOW (f->tool_bar_window);
   int area;
 
   /* Find the glyph under X/Y.  */
@@ -12109,7 +12233,7 @@ get_tool_bar_item (struct frame *f, int x, int y, struct glyph **glyph,
     return -1;
 
   /* Is mouse on the highlighted item?  */
-  if (EQ (FGET (f, tool_bar_window), hlinfo->mouse_face_window)
+  if (EQ (f->tool_bar_window, hlinfo->mouse_face_window)
       && *vpos >= hlinfo->mouse_face_beg_row
       && *vpos <= hlinfo->mouse_face_end_row
       && (*vpos > hlinfo->mouse_face_beg_row
@@ -12134,7 +12258,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
                       int modifiers)
 {
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
-  struct window *w = XWINDOW (FGET (f, tool_bar_window));
+  struct window *w = XWINDOW (f->tool_bar_window);
   int hpos, vpos, prop_idx;
   struct glyph *glyph;
   Lisp_Object enabled_p;
@@ -12145,7 +12269,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
     return;
 
   /* If item is disabled, do nothing.  */
-  enabled_p = AREF (FGET (f, tool_bar_items), prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+  enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
   if (NILP (enabled_p))
     return;
 
@@ -12153,7 +12277,6 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
     {
       /* Show item in pressed state.  */
       show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
-      hlinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
       last_tool_bar_item = prop_idx;
     }
   else
@@ -12164,9 +12287,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
 
       /* Show item in released state.  */
       show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
-      hlinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
 
-      key = AREF (FGET (f, tool_bar_items), prop_idx + TOOL_BAR_ITEM_KEY);
+      key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
 
       XSETFRAME (frame, f);
       event.kind = TOOL_BAR_EVENT;
@@ -12191,7 +12313,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
 static void
 note_tool_bar_highlight (struct frame *f, int x, int y)
 {
-  Lisp_Object window = FGET (f, tool_bar_window);
+  Lisp_Object window = f->tool_bar_window;
   struct window *w = XWINDOW (window);
   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
@@ -12233,11 +12355,10 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
       && last_tool_bar_item != prop_idx)
     return;
 
-  hlinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
 
   /* If tool-bar item is not enabled, don't highlight it.  */
-  enabled_p = AREF (FGET (f, tool_bar_items), prop_idx + TOOL_BAR_ITEM_ENABLED_P);
+  enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
   if (!NILP (enabled_p))
     {
       /* Compute the x-position of the glyph.  In front and past the
@@ -12262,7 +12383,6 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
 
       /* Display it as active.  */
       show_mouse_face (hlinfo, draw);
-      hlinfo->mouse_face_image_state = draw;
     }
 
  set_help_echo:
@@ -12271,9 +12391,9 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
      XTread_socket does the rest.  */
   help_echo_object = help_echo_window = Qnil;
   help_echo_pos = -1;
-  help_echo_string = AREF (FGET (f, tool_bar_items), prop_idx + TOOL_BAR_ITEM_HELP);
+  help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_HELP);
   if (NILP (help_echo_string))
-    help_echo_string = AREF (FGET (f, tool_bar_items), prop_idx + TOOL_BAR_ITEM_CAPTION);
+    help_echo_string = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_CAPTION);
 }
 
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -12323,10 +12443,10 @@ hscroll_window_tree (Lisp_Object window)
     {
       struct window *w = XWINDOW (window);
 
-      if (WINDOWP (WGET (w, hchild)))
-       hscrolled_p |= hscroll_window_tree (WGET (w, hchild));
-      else if (WINDOWP (WGET (w, vchild)))
-       hscrolled_p |= hscroll_window_tree (WGET (w, vchild));
+      if (WINDOWP (w->hchild))
+       hscrolled_p |= hscroll_window_tree (w->hchild);
+      else if (WINDOWP (w->vchild))
+       hscrolled_p |= hscroll_window_tree (w->vchild);
       else if (w->cursor.vpos >= 0)
        {
          int h_margin;
@@ -12346,7 +12466,7 @@ hscroll_window_tree (Lisp_Object window)
          /* Scroll when cursor is inside this scroll margin.  */
          h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
 
-         if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, WGET (w, buffer)))
+         if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer))
              /* 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
@@ -12381,16 +12501,12 @@ hscroll_window_tree (Lisp_Object window)
 
              /* Find point in a display of infinite width.  */
              saved_current_buffer = current_buffer;
-             current_buffer = XBUFFER (WGET (w, buffer));
+             current_buffer = XBUFFER (w->buffer);
 
              if (w == XWINDOW (selected_window))
                pt = PT;
              else
-               {
-                 pt = marker_position (WGET (w, pointm));
-                 pt = max (BEGV, pt);
-                 pt = min (ZV, pt);
-               }
+               pt = clip_to_bounds (BEGV, marker_position (w->pointm), ZV);
 
              /* Move iterator to pt starting at cursor_row->start in
                 a line with infinite width.  */
@@ -12438,14 +12554,14 @@ hscroll_window_tree (Lisp_Object window)
                 redisplay.  */
              if (w->hscroll != hscroll)
                {
-                 XBUFFER (WGET (w, buffer))->prevent_redisplay_optimizations_p = 1;
+                 XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
                  w->hscroll = hscroll;
                  hscrolled_p = 1;
                }
            }
        }
 
-      window = WGET (w, next);
+      window = w->next;
     }
 
   /* Value is non-zero if hscroll of any leaf window has been changed.  */
@@ -12527,9 +12643,9 @@ debug_method_add (struct window *w, char const *fmt, ...)
   if (trace_redisplay_p)
     fprintf (stderr, "%p (%s): %s\n",
             w,
-            ((BUFFERP (WGET (w, buffer))
-              && STRINGP (BVAR (XBUFFER (WGET (w, buffer)), name)))
-             ? SSDATA (BVAR (XBUFFER (WGET (w, buffer)), name))
+            ((BUFFERP (w->buffer)
+              && STRINGP (BVAR (XBUFFER (w->buffer), name)))
+             ? SSDATA (BVAR (XBUFFER (w->buffer), name))
              : "no buffer"),
             method + len);
 }
@@ -12542,15 +12658,14 @@ debug_method_add (struct window *w, char const *fmt, ...)
    buffer position, END is given as a distance from Z.  Used in
    redisplay_internal for display optimization.  */
 
-static inline int
+static int
 text_outside_line_unchanged_p (struct window *w,
                               ptrdiff_t start, ptrdiff_t end)
 {
   int unchanged_p = 1;
 
   /* If text or overlays have changed, see where.  */
-  if (w->last_modified < MODIFF
-      || w->last_overlay_modified < OVERLAY_MODIFF)
+  if (window_outdated (w))
     {
       /* Gap in the line?  */
       if (GPT < start || Z - GPT < end)
@@ -12594,8 +12709,8 @@ text_outside_line_unchanged_p (struct window *w,
         require to redisplay the whole paragraph.  It might be worthwhile
         to find the paragraph limits and widen the range of redisplayed
         lines to that, but for now just give up this optimization.  */
-      if (!NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering))
-         && NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_paragraph_direction)))
+      if (!NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering))
+         && NILP (BVAR (XBUFFER (w->buffer), bidi_paragraph_direction)))
        unchanged_p = 0;
     }
 
@@ -12753,7 +12868,7 @@ overlay_arrow_at_row (struct it *it, struct glyph_row *row)
                    return make_number (fringe_bitmap);
                }
 #endif
-             return make_number (-1); /* Use default arrow bitmap */
+             return make_number (-1); /* Use default arrow bitmap */
            }
          return overlay_arrow_string_or_property (var);
        }
@@ -12803,11 +12918,11 @@ check_point_in_composition (struct buffer *prev_buf, ptrdiff_t prev_pt,
 /* Reconsider the setting of B->clip_changed which is displayed
    in window W.  */
 
-static inline void
+static void
 reconsider_clip_changes (struct window *w, struct buffer *b)
 {
   if (b->clip_changed
-          && !NILP (WGET (w, window_end_valid))
+          && !NILP (w->window_end_valid)
           && w->current_matrix->buffer == b
           && w->current_matrix->zv == BUF_ZV (b)
           && w->current_matrix->begv == BUF_BEGV (b))
@@ -12819,56 +12934,25 @@ reconsider_clip_changes (struct window *w, struct buffer *b)
      b->clip_changed has already been set to 1, we can skip this
      check.  */
   if (!b->clip_changed
-      && BUFFERP (WGET (w, buffer)) && !NILP (WGET (w, window_end_valid)))
+      && BUFFERP (w->buffer) && !NILP (w->window_end_valid))
     {
       ptrdiff_t pt;
 
       if (w == XWINDOW (selected_window))
        pt = PT;
       else
-       pt = marker_position (WGET (w, pointm));
+       pt = marker_position (w->pointm);
 
-      if ((w->current_matrix->buffer != XBUFFER (WGET (w, buffer))
+      if ((w->current_matrix->buffer != XBUFFER (w->buffer)
           || pt != w->last_point)
          && check_point_in_composition (w->current_matrix->buffer,
                                         w->last_point,
-                                        XBUFFER (WGET (w, buffer)), pt))
+                                        XBUFFER (w->buffer), pt))
        b->clip_changed = 1;
     }
 }
 \f
 
-/* Select FRAME to forward the values of frame-local variables into C
-   variables so that the redisplay routines can access those values
-   directly.  */
-
-static void
-select_frame_for_redisplay (Lisp_Object frame)
-{
-  Lisp_Object tail, tem;
-  Lisp_Object old = selected_frame;
-  struct Lisp_Symbol *sym;
-
-  eassert (FRAMEP (frame) && FRAME_LIVE_P (XFRAME (frame)));
-
-  selected_frame = frame;
-
-  do {
-    for (tail = FGET (XFRAME (frame), param_alist);
-        CONSP (tail); tail = XCDR (tail))
-      if (CONSP (XCAR (tail))
-         && (tem = XCAR (XCAR (tail)),
-             SYMBOLP (tem))
-         && (sym = indirect_variable (XSYMBOL (tem)),
-             sym->redirect == SYMBOL_LOCALIZED)
-         && sym->val.blv->frame_local)
-       /* Use find_symbol_value rather than Fsymbol_value
-          to avoid an error if it is void.  */
-       find_symbol_value (tem);
-  } while (!EQ (frame, old) && (frame = old, 1));
-}
-
-
 #define STOP_POLLING                                   \
 do { if (! polling_stopped_here) stop_polling ();      \
        polling_stopped_here = 1; } while (0)
@@ -12894,13 +12978,14 @@ redisplay_internal (void)
   ptrdiff_t count, count1;
   struct frame *sf;
   int polling_stopped_here = 0;
-  Lisp_Object old_frame = selected_frame;
+  Lisp_Object tail, frame;
+  struct backtrace backtrace;
 
   /* Non-zero means redisplay has to consider all windows on all
      frames.  Zero means, only selected_window is considered.  */
   int consider_all_windows_p;
 
-  /* Non-zero means redisplay has to redisplay the miniwindow */
+  /* Non-zero means redisplay has to redisplay the miniwindow */
   int update_miniwindow_p = 0;
 
   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
@@ -12915,7 +13000,7 @@ redisplay_internal (void)
   /* Don't examine these until after testing Vinhibit_redisplay.
      When Emacs is shutting down, perhaps because its connection to
      X has dropped, we should not look at them at all.  */
-  fr = XFRAME (WGET (w, frame));
+  fr = XFRAME (w->frame);
   sf = SELECTED_FRAME ();
 
   if (!fr->glyphs_initialized_p)
@@ -12930,36 +13015,28 @@ redisplay_internal (void)
   if (redisplaying_p)
     return;
 
-  /* Record a function that resets redisplaying_p to its old value
+  /* Record a function that clears redisplaying_p
      when we leave this function.  */
   count = SPECPDL_INDEX ();
-  record_unwind_protect (unwind_redisplay,
-                        Fcons (make_number (redisplaying_p), selected_frame));
-  ++redisplaying_p;
+  record_unwind_protect (unwind_redisplay, selected_frame);
+  redisplaying_p = 1;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
-  {
-    Lisp_Object tail, frame;
+  /* Record this function, so it appears on the profiler's backtraces.  */
+  backtrace.next = backtrace_list;
+  backtrace.function = Qredisplay_internal;
+  backtrace.args = &Qnil;
+  backtrace.nargs = 0;
+  backtrace.debug_on_exit = 0;
+  backtrace_list = &backtrace;
 
-    FOR_EACH_FRAME (tail, frame)
-      {
-       struct frame *f = XFRAME (frame);
-       f->already_hscrolled_p = 0;
-      }
-  }
+  FOR_EACH_FRAME (tail, frame)
+    XFRAME (frame)->already_hscrolled_p = 0;
 
  retry:
   /* Remember the currently selected window.  */
   sw = w;
 
-  if (!EQ (old_frame, selected_frame)
-      && FRAME_LIVE_P (XFRAME (old_frame)))
-    /* When running redisplay, we play a bit fast-and-loose and allow e.g.
-       selected_frame and selected_window to be temporarily out-of-sync so
-       when we come back here via `goto retry', we need to resync because we
-       may need to run Elisp code (via prepare_menu_bars).  */
-    select_frame_for_redisplay (old_frame);
-
   pending = 0;
   reconsider_clip_changes (w, current_buffer);
   last_escape_glyph_frame = NULL;
@@ -12996,25 +13073,20 @@ redisplay_internal (void)
       FRAME_TTY (sf)->previous_frame = sf;
     }
 
-  /* Set the visible flags for all frames.  Do this before checking
-     for resized or garbaged frames; they want to know if their frames
-     are visible.  See the comment in frame.h for
-     FRAME_SAMPLE_VISIBILITY.  */
-  {
-    Lisp_Object tail, frame;
-
-    number_of_visible_frames = 0;
+  /* Set the visible flags for all frames.  Do this before checking for
+     resized or garbaged frames; they want to know if their frames are
+     visible.  See the comment in frame.h for FRAME_SAMPLE_VISIBILITY.  */
+  number_of_visible_frames = 0;
 
-    FOR_EACH_FRAME (tail, frame)
-      {
-       struct frame *f = XFRAME (frame);
+  FOR_EACH_FRAME (tail, frame)
+    {
+      struct frame *f = XFRAME (frame);
 
-       FRAME_SAMPLE_VISIBILITY (f);
-       if (FRAME_VISIBLE_P (f))
-         ++number_of_visible_frames;
-       clear_desired_matrices (f);
-      }
-  }
+      FRAME_SAMPLE_VISIBILITY (f);
+      if (FRAME_VISIBLE_P (f))
+       ++number_of_visible_frames;
+      clear_desired_matrices (f);
+    }
 
   /* Notice any pending interrupt request to change frame size.  */
   do_pending_window_change (1);
@@ -13028,8 +13100,7 @@ redisplay_internal (void)
     }
 
   /* Clear frames marked as garbaged.  */
-  if (frame_garbaged)
-    clear_garbaged_frames ();
+  clear_garbaged_frames ();
 
   /* Build menubar and tool-bar items.  */
   if (NILP (Vmemory_full))
@@ -13042,7 +13113,7 @@ redisplay_internal (void)
   if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
     {
       w->update_mode_line = 1;
-      if (buffer_shared > 1)
+      if (buffer_shared_and_changed ())
        update_mode_lines++;
     }
 
@@ -13050,24 +13121,15 @@ redisplay_internal (void)
   count1 = SPECPDL_INDEX ();
   specbind (Qinhibit_point_motion_hooks, Qt);
 
-  /* If %c is in the mode line, update it if needed.  */
-  if (!NILP (WGET (w, column_number_displayed))
-      /* This alternative quickly identifies a common case
-        where no change is needed.  */
-      && !(PT == w->last_point
-          && w->last_modified >= MODIFF
-          && w->last_overlay_modified >= OVERLAY_MODIFF)
-      && (XFASTINT (WGET (w, column_number_displayed)) != current_column ()))
+  if (mode_line_update_needed (w))
     w->update_mode_line = 1;
 
   unbind_to (count1, Qnil);
 
-  FRAME_SCROLL_BOTTOM_VPOS (XFRAME (WGET (w, frame))) = -1;
+  FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
 
-  /* The variable buffer_shared is set in redisplay_window and
-     indicates that we redisplay a buffer in different windows.  See
-     there.  */
-  consider_all_windows_p = (update_mode_lines || buffer_shared > 1
+  consider_all_windows_p = (update_mode_lines
+                           || buffer_shared_and_changed ()
                            || cursor_type_changed);
 
   /* If specs for an arrow have changed, do thorough redisplay
@@ -13113,23 +13175,20 @@ redisplay_internal (void)
          /* If window configuration was changed, frames may have been
             marked garbaged.  Clear them or we will experience
             surprises wrt scrolling.  */
-         if (frame_garbaged)
-           clear_garbaged_frames ();
+         clear_garbaged_frames ();
        }
     }
   else if (EQ (selected_window, minibuf_window)
-          && (current_buffer->clip_changed
-              || w->last_modified < MODIFF
-              || w->last_overlay_modified < OVERLAY_MODIFF)
+          && (current_buffer->clip_changed || window_outdated (w))
           && resize_mini_window (w, 0))
     {
       /* Resized active mini-window to fit the size of what it is
          showing if its contents might have changed.  */
       must_finish = 1;
-/* 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.  */
+      /* 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;
@@ -13137,8 +13196,7 @@ redisplay_internal (void)
       /* If window configuration was changed, frames may have been
         marked garbaged.  Clear them or we will experience
         surprises wrt scrolling.  */
-      if (frame_garbaged)
-       clear_garbaged_frames ();
+      clear_garbaged_frames ();
     }
 
 
@@ -13146,11 +13204,11 @@ redisplay_internal (void)
      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 (WGET (w, buffer)), mark_active)))
-       != !NILP (WGET (w, region_showing)))
-      || (!NILP (WGET (w, region_showing))
-         && !EQ (WGET (w, region_showing),
-                 Fmarker_position (BVAR (XBUFFER (WGET (w, buffer)), mark)))))
+       && !NILP (BVAR (XBUFFER (w->buffer), mark_active)))
+       != !NILP (w->region_showing))
+      || (!NILP (w->region_showing)
+         && !EQ (w->region_showing,
+                 Fmarker_position (BVAR (XBUFFER (w->buffer), mark)))))
     CHARPOS (this_line_start_pos) = 0;
 
   /* Optimize the case that only the line containing the cursor in the
@@ -13164,11 +13222,11 @@ redisplay_internal (void)
       && !w->update_mode_line
       && !current_buffer->clip_changed
       && !current_buffer->prevent_redisplay_optimizations_p
-      && FRAME_VISIBLE_P (XFRAME (WGET (w, frame)))
-      && !FRAME_OBSCURED_P (XFRAME (WGET (w, frame)))
+      && FRAME_VISIBLE_P (XFRAME (w->frame))
+      && !FRAME_OBSCURED_P (XFRAME (w->frame))
       /* Make sure recorded data applies to current buffer, etc.  */
       && this_line_buffer == current_buffer
-      && current_buffer == XBUFFER (WGET (w, buffer))
+      && current_buffer == XBUFFER (w->buffer)
       && !w->force_start
       && !w->optional_new_start
       /* Point must be on the line that we have info recorded about.  */
@@ -13185,9 +13243,7 @@ redisplay_internal (void)
              || FETCH_BYTE (BYTEPOS (tlbufpos)) == '\n'))
        /* Former continuation line has disappeared by becoming empty.  */
        goto cancel;
-      else if (w->last_modified < MODIFF
-              || w->last_overlay_modified < OVERLAY_MODIFF
-              || MINI_WINDOW_P (w))
+      else if (window_outdated (w) || MINI_WINDOW_P (w))
        {
          /* We have to handle the case of continuation around a
             wide-column character (see the comment in indent.c around
@@ -13266,13 +13322,13 @@ redisplay_internal (void)
                 adjusted.  */
              if ((it.glyph_row - 1)->displays_text_p)
                {
-                 if (XFASTINT (WGET (w, window_end_vpos)) < this_line_vpos)
-                   WSET (w, window_end_vpos, make_number (this_line_vpos));
+                 if (XFASTINT (w->window_end_vpos) < this_line_vpos)
+                   wset_window_end_vpos (w, make_number (this_line_vpos));
                }
-             else if (XFASTINT (WGET (w, window_end_vpos)) == this_line_vpos
+             else if (XFASTINT (w->window_end_vpos) == this_line_vpos
                       && this_line_vpos > 0)
-               WSET (w, window_end_vpos, make_number (this_line_vpos - 1));
-             WSET (w, window_end_valid, Qnil);
+               wset_window_end_vpos (w, make_number (this_line_vpos - 1));
+             wset_window_end_valid (w, Qnil);
 
              /* Update hint: No need to try to scroll in update_window.  */
              w->desired_matrix->no_scrolling_p = 1;
@@ -13318,7 +13374,7 @@ redisplay_internal (void)
               && (EQ (selected_window,
                       BVAR (current_buffer, last_selected_window))
                   || highlight_nonselected_windows)
-              && NILP (WGET (w, region_showing))
+              && NILP (w->region_showing)
               && NILP (Vshow_trailing_whitespace)
               && !cursor_in_echo_area)
        {
@@ -13361,7 +13417,7 @@ redisplay_internal (void)
     }
 
   CHARPOS (this_line_start_pos) = 0;
-  consider_all_windows_p |= buffer_shared > 1;
+  consider_all_windows_p |= buffer_shared_and_changed ();
   ++clear_face_cache_count;
 #ifdef HAVE_WINDOW_SYSTEM
   ++clear_image_cache_count;
@@ -13373,15 +13429,9 @@ redisplay_internal (void)
 
   if (consider_all_windows_p)
     {
-      Lisp_Object tail, frame;
-
       FOR_EACH_FRAME (tail, frame)
        XFRAME (frame)->updated_p = 0;
 
-      /* Recompute # windows showing selected buffer.  This will be
-        incremented each time such a window is displayed.  */
-      buffer_shared = 0;
-
       FOR_EACH_FRAME (tail, frame)
        {
          struct frame *f = XFRAME (frame);
@@ -13394,11 +13444,6 @@ redisplay_internal (void)
 
          if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
            {
-             if (! EQ (frame, selected_frame))
-               /* Select the frame, for the sake of frame-local
-                  variables.  */
-               select_frame_for_redisplay (frame);
-
              /* 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)
@@ -13428,7 +13473,7 @@ redisplay_internal (void)
                  if (!f->already_hscrolled_p)
                    {
                      f->already_hscrolled_p = 1;
-                     if (hscroll_windows (FGET (f, root_window)))
+                     if (hscroll_windows (f->root_window))
                        goto retry;
                    }
 
@@ -13441,21 +13486,14 @@ redisplay_internal (void)
                  STOP_POLLING;
 
                  /* Update the display.  */
-                 set_window_update_flags (XWINDOW (FGET (f, root_window)), 1);
+                 set_window_update_flags (XWINDOW (f->root_window), 1);
                  pending |= update_frame (f, 0, 0);
                  f->updated_p = 1;
                }
            }
        }
 
-      if (!EQ (old_frame, selected_frame)
-         && FRAME_LIVE_P (XFRAME (old_frame)))
-       /* We played a bit fast-and-loose above and allowed selected_frame
-          and selected_window to be temporarily out-of-sync but let's make
-          sure this stays contained.  */
-       select_frame_for_redisplay (old_frame);
-      eassert (EQ (FGET (XFRAME (selected_frame), selected_window),
-                  selected_window));
+      eassert (EQ (XFRAME (selected_frame)->selected_window, selected_window));
 
       if (!pending)
        {
@@ -13467,7 +13505,7 @@ redisplay_internal (void)
              struct frame *f = XFRAME (frame);
               if (f->updated_p)
                 {
-                  mark_window_display_accurate (FGET (f, root_window), 1);
+                  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);
                 }
@@ -13479,7 +13517,7 @@ redisplay_internal (void)
       Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
       struct frame *mini_frame;
 
-      displayed_buffer = XBUFFER (WGET (XWINDOW (selected_window), buffer));
+      displayed_buffer = XBUFFER (XWINDOW (selected_window)->buffer);
       /* Use list_of_error, not Qerror, so that
         we catch only errors and don't run the debugger.  */
       internal_condition_case_1 (redisplay_window_1, selected_window,
@@ -13545,7 +13583,7 @@ redisplay_internal (void)
       /* If we pause after scrolling, some rows in the current
         matrices of some windows are not valid.  */
       if (!WINDOW_FULL_WIDTH_P (w)
-         && !FRAME_WINDOW_P (XFRAME (WGET (w, frame))))
+         && !FRAME_WINDOW_P (XFRAME (w->frame)))
        update_mode_lines = 1;
     }
   else
@@ -13584,7 +13622,6 @@ redisplay_internal (void)
      frames here explicitly.  */
   if (!pending)
     {
-      Lisp_Object tail, frame;
       int new_count = 0;
 
       FOR_EACH_FRAME (tail, frame)
@@ -13635,6 +13672,7 @@ redisplay_internal (void)
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
+  backtrace_list = backtrace.next;
   unbind_to (count, Qnil);
   RESUME_POLLING;
 }
@@ -13673,24 +13711,13 @@ redisplay_preserve_echo_area (int from_where)
 }
 
 
-/* Function registered with record_unwind_protect in
-   redisplay_internal.  Reset redisplaying_p to the value it had
-   before redisplay_internal was called, and clear
-   prevent_freeing_realized_faces_p.  It also selects the previously
-   selected frame, unless it has been deleted (by an X connection
-   failure during redisplay, for example).  */
+/* Function registered with record_unwind_protect in redisplay_internal.
+   Clear redisplaying_p.  Also select the previously selected frame.  */
 
 static Lisp_Object
-unwind_redisplay (Lisp_Object val)
+unwind_redisplay (Lisp_Object old_frame)
 {
-  Lisp_Object old_redisplaying_p, old_frame;
-
-  old_redisplaying_p = XCAR (val);
-  redisplaying_p = XFASTINT (old_redisplaying_p);
-  old_frame = XCDR (val);
-  if (! EQ (old_frame, selected_frame)
-      && FRAME_LIVE_P (XFRAME (old_frame)))
-    select_frame_for_redisplay (old_frame);
+  redisplaying_p = 0;
   return Qnil;
 }
 
@@ -13703,12 +13730,12 @@ unwind_redisplay (Lisp_Object val)
 static void
 mark_window_display_accurate_1 (struct window *w, int accurate_p)
 {
-  if (BUFFERP (WGET (w, buffer)))
+  if (BUFFERP (w->buffer))
     {
-      struct buffer *b = XBUFFER (WGET (w, buffer));
+      struct buffer *b = XBUFFER (w->buffer);
 
-      w->last_modified = accurate_p ? BUF_MODIFF(b) : 0;
-      w->last_overlay_modified = accurate_p ? BUF_OVERLAY_MODIFF(b) : 0;
+      w->last_modified = accurate_p ? BUF_MODIFF (b) : 0;
+      w->last_overlay_modified = accurate_p ? BUF_OVERLAY_MODIFF (b) : 0;
       w->last_had_star
        = BUF_MODIFF (b) > BUF_SAVE_MODIFF (b);
 
@@ -13732,13 +13759,13 @@ mark_window_display_accurate_1 (struct window *w, int accurate_p)
          if (w == XWINDOW (selected_window))
            w->last_point = BUF_PT (b);
          else
-           w->last_point = XMARKER (WGET (w, pointm))->charpos;
+           w->last_point = marker_position (w->pointm);
        }
     }
 
   if (accurate_p)
     {
-      WSET (w, window_end_valid, WGET (w, buffer));
+      wset_window_end_valid (w, w->buffer);
       w->update_mode_line = 0;
     }
 }
@@ -13754,15 +13781,15 @@ mark_window_display_accurate (Lisp_Object window, int accurate_p)
 {
   struct window *w;
 
-  for (; !NILP (window); window = WGET (w, next))
+  for (; !NILP (window); window = w->next)
     {
       w = XWINDOW (window);
       mark_window_display_accurate_1 (w, accurate_p);
 
-      if (!NILP (WGET (w, vchild)))
-       mark_window_display_accurate (WGET (w, vchild), accurate_p);
-      if (!NILP (WGET (w, hchild)))
-       mark_window_display_accurate (WGET (w, hchild), accurate_p);
+      if (!NILP (w->vchild))
+       mark_window_display_accurate (w->vchild, accurate_p);
+      if (!NILP (w->hchild))
+       mark_window_display_accurate (w->hchild, accurate_p);
     }
 
   if (accurate_p)
@@ -13822,13 +13849,13 @@ redisplay_windows (Lisp_Object window)
     {
       struct window *w = XWINDOW (window);
 
-      if (!NILP (WGET (w, hchild)))
-       redisplay_windows (WGET (w, hchild));
-      else if (!NILP (WGET (w, vchild)))
-       redisplay_windows (WGET (w, vchild));
-      else if (!NILP (WGET (w, buffer)))
+      if (!NILP (w->hchild))
+       redisplay_windows (w->hchild);
+      else if (!NILP (w->vchild))
+       redisplay_windows (w->vchild);
+      else if (!NILP (w->buffer))
        {
-         displayed_buffer = XBUFFER (WGET (w, buffer));
+         displayed_buffer = XBUFFER (w->buffer);
          /* Use list_of_error, not Qerror, so that
             we catch only errors and don't run the debugger.  */
          internal_condition_case_1 (redisplay_window_0, window,
@@ -13836,7 +13863,7 @@ redisplay_windows (Lisp_Object window)
                                     redisplay_window_error);
        }
 
-      window = WGET (w, next);
+      window = w->next;
     }
 }
 
@@ -14154,7 +14181,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
      GLYPH_BEFORE and GLYPH_AFTER.  */
   if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
        && BUFFERP (glyph->object) && glyph->charpos == pt_old)
-      && bpos_covered < pt_old)
+      && !(bpos_max < pt_old && pt_old <= bpos_covered))
     {
       /* An empty line has a single glyph whose OBJECT is zero and
         whose CHARPOS is the position of a newline on that line.
@@ -14163,7 +14190,12 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
         CHARPOS is zero or negative.  */
       int empty_line_p =
        (row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
-       && INTEGERP (glyph->object) && glyph->charpos > 0;
+       && INTEGERP (glyph->object) && glyph->charpos > 0
+       /* On a TTY, continued and truncated rows also have a glyph at
+          their end whose OBJECT is zero and whose CHARPOS is
+          positive (the continuation and truncation glyphs), but such
+          rows are obviously not "empty".  */
+       && !(row->continued_p || row->truncated_on_right_p);
 
       if (row->ends_in_ellipsis_p && pos_after == last_pos)
        {
@@ -14386,7 +14418,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
       for (g = row->glyphs[TEXT_AREA], x = row->x; g < glyph; g++)
        {
          if (g >= row->glyphs[TEXT_AREA] + row->used[TEXT_AREA])
-           abort ();
+           emacs_abort ();
          x += g->pixel_width;
        }
     }
@@ -14470,7 +14502,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
          && !MATRIX_ROW_CONTINUATION_LINE_P (row)
          && row->x == 0)
        {
-         this_line_buffer = XBUFFER (WGET (w, buffer));
+         this_line_buffer = XBUFFER (w->buffer);
 
          CHARPOS (this_line_start_pos)
            = MATRIX_ROW_START_CHARPOS (row) + delta;
@@ -14500,23 +14532,22 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
 
    We assume that the window's buffer is really current.  */
 
-static inline struct text_pos
+static struct text_pos
 run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
 {
   struct window *w = XWINDOW (window);
-  SET_MARKER_FROM_TEXT_POS (WGET (w, start), startp);
+  SET_MARKER_FROM_TEXT_POS (w->start, startp);
 
-  if (current_buffer != XBUFFER (WGET (w, buffer)))
-    abort ();
+  if (current_buffer != XBUFFER (w->buffer))
+    emacs_abort ();
 
   if (!NILP (Vwindow_scroll_functions))
     {
       run_hook_with_args_2 (Qwindow_scroll_functions, window,
                            make_number (CHARPOS (startp)));
-      SET_TEXT_POS_FROM_MARKER (startp, WGET (w, start));
+      SET_TEXT_POS_FROM_MARKER (startp, w->start);
       /* In case the hook functions switch buffers.  */
-      if (current_buffer != XBUFFER (WGET (w, buffer)))
-       set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+      set_buffer_internal (XBUFFER (w->buffer));
     }
 
   return startp;
@@ -14606,7 +14637,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
               int temp_scroll_step, int last_line_misfit)
 {
   struct window *w = XWINDOW (window);
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   struct text_pos pos, startp;
   struct it it;
   int this_scroll_margin, scroll_max, rc, height;
@@ -14620,7 +14651,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   debug_method_add (w, "try_scrolling");
 #endif
 
-  SET_TEXT_POS_FROM_MARKER (startp, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (startp, w->start);
 
   /* Compute scroll margin height in pixels.  We scroll when point is
      within this distance from the top or bottom of the window.  */
@@ -14714,13 +14745,18 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          if (NUMBERP (aggressive))
            {
              double float_amount = XFLOATINT (aggressive) * height;
-             amount_to_scroll = float_amount;
-             if (amount_to_scroll == 0 && float_amount > 0)
-               amount_to_scroll = 1;
+             int aggressive_scroll = float_amount;
+             if (aggressive_scroll == 0 && float_amount > 0)
+               aggressive_scroll = 1;
              /* Don't let point enter the scroll margin near top of
-                the window.  */
-             if (amount_to_scroll > height - 2*this_scroll_margin + dy)
-               amount_to_scroll = height - 2*this_scroll_margin + dy;
+                the window.  This could happen if the value of
+                scroll_up_aggressively is too large and there are
+                non-zero margins, because scroll_up_aggressively
+                means put point that fraction of window height
+                _from_the_bottom_margin_.  */
+             if (aggressive_scroll + 2*this_scroll_margin > height)
+               aggressive_scroll = height - 2*this_scroll_margin;
+             amount_to_scroll = dy + aggressive_scroll;
            }
        }
 
@@ -14780,7 +14816,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          /* Compute the vertical distance from PT to the scroll
             margin position.  Move as far as scroll_max allows, or
             one screenful, or 10 screen lines, whichever is largest.
-            Give up if distance is greater than scroll_max.  */
+            Give up if distance is greater than scroll_max or if we
+            didn't reach the scroll margin position.  */
          SET_TEXT_POS (pos, PT, PT_BYTE);
          start_display (&it, w, pos);
          y0 = it.current_y;
@@ -14790,7 +14827,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
                      y_to_move, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
          dy = it.current_y - y0;
-         if (dy > scroll_max)
+         if (dy > scroll_max
+             || IT_CHARPOS (it) < CHARPOS (scroll_margin_pos))
            return SCROLLING_FAILED;
 
          /* Compute new window start.  */
@@ -14808,15 +14846,16 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
              if (NUMBERP (aggressive))
                {
                  double float_amount = XFLOATINT (aggressive) * height;
-                 amount_to_scroll = float_amount;
-                 if (amount_to_scroll == 0 && float_amount > 0)
-                   amount_to_scroll = 1;
-                 amount_to_scroll -=
-                   this_scroll_margin - dy - FRAME_LINE_HEIGHT (f);
+                 int aggressive_scroll = float_amount;
+                 if (aggressive_scroll == 0 && float_amount > 0)
+                   aggressive_scroll = 1;
                  /* Don't let point enter the scroll margin near
-                    bottom of the window.  */
-                 if (amount_to_scroll > height - 2*this_scroll_margin + dy)
-                   amount_to_scroll = height - 2*this_scroll_margin + dy;
+                    bottom of the window, if the value of
+                    scroll_down_aggressively happens to be too
+                    large.  */
+                 if (aggressive_scroll + 2*this_scroll_margin > height)
+                   aggressive_scroll = height - 2*this_scroll_margin;
+                 amount_to_scroll = dy + aggressive_scroll;
                }
            }
 
@@ -14846,7 +14885,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
       if (!just_this_one_p
          || current_buffer->clip_changed
          || BEG_UNCHANGED < CHARPOS (startp))
-       WSET (w, base_line_number, Qnil);
+       wset_base_line_number (w, Qnil);
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
@@ -14881,7 +14920,7 @@ compute_window_start_on_continuation_line (struct window *w)
   struct text_pos pos, start_pos;
   int window_start_changed_p = 0;
 
-  SET_TEXT_POS_FROM_MARKER (start_pos, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (start_pos, w->start);
 
   /* If window start is on a continuation line...  Window start may be
      < BEGV in case there's invisible text at the start of the
@@ -14929,7 +14968,7 @@ compute_window_start_on_continuation_line (struct window *w)
            }
 
          /* Set the window start there.  */
-         SET_MARKER_FROM_TEXT_POS (WGET (w, start), pos);
+         SET_MARKER_FROM_TEXT_POS (w->start, pos);
          window_start_changed_p = 1;
        }
     }
@@ -14965,7 +15004,7 @@ static int
 try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_step)
 {
   struct window *w = XWINDOW (window);
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int rc = CURSOR_MOVEMENT_CANNOT_BE_USED;
 
 #ifdef GLYPH_DEBUG
@@ -14994,9 +15033,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
       /* Can't use this case if highlighting a region.  When a
          region exists, cursor movement has to do more than just
          set the cursor.  */
-      && !(!NILP (Vtransient_mark_mode)
-          && !NILP (BVAR (current_buffer, mark_active)))
-      && NILP (WGET (w, region_showing))
+      && markpos_of_region () < 0
+      && NILP (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
@@ -15010,8 +15048,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
         larger than the window.  This should really be fixed in
         window.c.  I don't have this on my list, now, so we do
         approximately the same as the old redisplay code.  --gerd.  */
-      && INTEGERP (WGET (w, window_end_vpos))
-      && XFASTINT (WGET (w, window_end_vpos)) < w->current_matrix->nrows
+      && INTEGERP (w->window_end_vpos)
+      && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
       && (FRAME_WINDOW_P (f)
          || !overlay_arrow_in_current_buffer_p ()))
     {
@@ -15148,7 +15186,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
              must_scroll = 1;
            }
          else if (rc != CURSOR_MOVEMENT_SUCCESS
-                  && !NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering)))
+                  && !NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering)))
            {
              struct glyph_row *row1;
 
@@ -15211,7 +15249,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
          else if (scroll_p)
            rc = CURSOR_MOVEMENT_MUST_SCROLL;
          else if (rc != CURSOR_MOVEMENT_SUCCESS
-                  && !NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering)))
+                  && !NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering)))
            {
              /* With bidi-reordered rows, there could be more than
                 one candidate row whose start and end positions
@@ -15318,12 +15356,12 @@ set_vertical_scroll_bar (struct window *w)
       || (w == XWINDOW (minibuf_window)
          && NILP (echo_area_buffer[0])))
     {
-      struct buffer *buf = XBUFFER (WGET (w, buffer));
+      struct buffer *buf = XBUFFER (w->buffer);
       whole = BUF_ZV (buf) - BUF_BEGV (buf);
-      start = marker_position (WGET (w, start)) - BUF_BEGV (buf);
+      start = marker_position (w->start) - BUF_BEGV (buf);
       /* I don't think this is guaranteed to be right.  For the
         moment, we'll pretend it is.  */
-      end = BUF_Z (buf) - XFASTINT (WGET (w, window_end_pos)) - BUF_BEGV (buf);
+      end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
 
       if (end < start)
        end = start;
@@ -15334,8 +15372,8 @@ set_vertical_scroll_bar (struct window *w)
     start = end = whole = 0;
 
   /* Indicate what this scroll bar ought to be displaying now.  */
-  if (FRAME_TERMINAL (XFRAME (WGET (w, frame)))->set_vertical_scroll_bar_hook)
-    (*FRAME_TERMINAL (XFRAME (WGET (w, frame)))->set_vertical_scroll_bar_hook)
+  if (FRAME_TERMINAL (XFRAME (w->frame))->set_vertical_scroll_bar_hook)
+    (*FRAME_TERMINAL (XFRAME (w->frame))->set_vertical_scroll_bar_hook)
       (w, end - start, whole, start);
 }
 
@@ -15344,15 +15382,15 @@ set_vertical_scroll_bar (struct window *w)
    selected_window is redisplayed.
 
    We can return without actually redisplaying the window if
-   fonts_changed_p is nonzero.  In that case, redisplay_internal will
+   fonts_changed_p.  In that case, redisplay_internal will
    retry.  */
 
 static void
 redisplay_window (Lisp_Object window, int just_this_one_p)
 {
   struct window *w = XWINDOW (window);
-  struct frame *f = XFRAME (WGET (w, frame));
-  struct buffer *buffer = XBUFFER (WGET (w, buffer));
+  struct frame *f = XFRAME (w->frame);
+  struct buffer *buffer = XBUFFER (w->buffer);
   struct buffer *old = current_buffer;
   struct text_pos lpoint, opoint, startp;
   int update_mode_line;
@@ -15375,7 +15413,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   opoint = lpoint;
 
   /* W must be a leaf window here.  */
-  eassert (!NILP (WGET (w, buffer)));
+  eassert (!NILP (w->buffer));
 #ifdef GLYPH_DEBUG
   *w->desired_matrix->method = 0;
 #endif
@@ -15405,10 +15443,10 @@ 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. */
-              && BUF_Z (XBUFFER (WGET (w, buffer))) == BUF_BEG (XBUFFER (WGET (w, buffer)))
+              && BUF_Z (XBUFFER (w->buffer)) == BUF_BEG (XBUFFER (w->buffer))
               /* Quail displays non-mini buffers in minibuffer window.
                  In that case, redisplay the window normally.  */
-              && !NILP (Fmemq (WGET (w, buffer), Vminibuffer_list)))
+              && !NILP (Fmemq (w->buffer, Vminibuffer_list)))
        {
          /* W is a mini-buffer window, but it's not active, so clear
             it.  */
@@ -15430,14 +15468,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
      value.  */
   /* Really select the buffer, for the sake of buffer-local
      variables.  */
-  set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+  set_buffer_internal_1 (XBUFFER (w->buffer));
 
   current_matrix_up_to_date_p
-    = (!NILP (WGET (w, window_end_valid))
+    = (!NILP (w->window_end_valid)
        && !current_buffer->clip_changed
        && !current_buffer->prevent_redisplay_optimizations_p
-       && w->last_modified >= MODIFF
-       && w->last_overlay_modified >= OVERLAY_MODIFF);
+       && !window_outdated (w));
 
   /* Run the window-bottom-change-functions
      if it is possible that the text on the screen has changed
@@ -15457,10 +15494,9 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   specbind (Qinhibit_point_motion_hooks, Qt);
 
   buffer_unchanged_p
-    = (!NILP (WGET (w, window_end_valid))
+    = (!NILP (w->window_end_valid)
        && !current_buffer->clip_changed
-       && w->last_modified >= MODIFF
-       && w->last_overlay_modified >= OVERLAY_MODIFF);
+       && !window_outdated (w));
 
   /* When windows_or_buffers_changed is non-zero, we can't rely on
      the window end being valid, so set it to nil there.  */
@@ -15468,61 +15504,39 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
     {
       /* If window starts on a continuation line, maybe adjust the
         window start in case the window's width changed.  */
-      if (XMARKER (WGET (w, start))->buffer == current_buffer)
+      if (XMARKER (w->start)->buffer == current_buffer)
        compute_window_start_on_continuation_line (w);
 
-      WSET (w, window_end_valid, Qnil);
+      wset_window_end_valid (w, Qnil);
     }
 
   /* Some sanity checks.  */
   CHECK_WINDOW_END (w);
   if (Z == Z_BYTE && CHARPOS (opoint) != BYTEPOS (opoint))
-    abort ();
+    emacs_abort ();
   if (BYTEPOS (opoint) < CHARPOS (opoint))
-    abort ();
-
-  /* If %c is in mode line, update it if needed.  */
-  if (!NILP (WGET (w, column_number_displayed))
-      /* This alternative quickly identifies a common case
-        where no change is needed.  */
-      && !(PT == w->last_point
-          && w->last_modified >= MODIFF
-          && w->last_overlay_modified >= OVERLAY_MODIFF)
-      && (XFASTINT (WGET (w, column_number_displayed)) != current_column ()))
-    update_mode_line = 1;
+    emacs_abort ();
 
-  /* Count number of windows showing the selected buffer.  An indirect
-     buffer counts as its base buffer.  */
-  if (!just_this_one_p)
-    {
-      struct buffer *current_base, *window_base;
-      current_base = current_buffer;
-      window_base = XBUFFER (WGET (XWINDOW (selected_window), buffer));
-      if (current_base->base_buffer)
-       current_base = current_base->base_buffer;
-      if (window_base->base_buffer)
-       window_base = window_base->base_buffer;
-      if (current_base == window_base)
-       buffer_shared++;
-    }
+  if (mode_line_update_needed (w))
+    update_mode_line = 1;
 
   /* Point refers normally to the selected window.  For any other
      window, set up appropriate value.  */
   if (!EQ (window, selected_window))
     {
-      ptrdiff_t new_pt = XMARKER (WGET (w, pointm))->charpos;
-      ptrdiff_t new_pt_byte = marker_byte_position (WGET (w, pointm));
+      ptrdiff_t new_pt = marker_position (w->pointm);
+      ptrdiff_t new_pt_byte = marker_byte_position (w->pointm);
       if (new_pt < BEGV)
        {
          new_pt = BEGV;
          new_pt_byte = BEGV_BYTE;
-         set_marker_both (WGET (w, pointm), Qnil, BEGV, BEGV_BYTE);
+         set_marker_both (w->pointm, Qnil, BEGV, BEGV_BYTE);
        }
       else if (new_pt > (ZV - 1))
        {
          new_pt = ZV;
          new_pt_byte = ZV_BYTE;
-         set_marker_both (WGET (w, pointm), Qnil, ZV, ZV_BYTE);
+         set_marker_both (w->pointm, Qnil, ZV, ZV_BYTE);
        }
 
       /* We don't use SET_PT so that the point-motion hooks don't run.  */
@@ -15549,10 +15563,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
     }
 
   /* If window-start is screwed up, choose a new one.  */
-  if (XMARKER (WGET (w, start))->buffer != current_buffer)
+  if (XMARKER (w->start)->buffer != current_buffer)
     goto recenter;
 
-  SET_TEXT_POS_FROM_MARKER (startp, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (startp, w->start);
 
   /* If someone specified a new starting point but did not insist,
      check whether it can be used.  */
@@ -15582,11 +15596,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
       w->force_start = 0;
       w->vscroll = 0;
-      WSET (w, window_end_valid, Qnil);
+      wset_window_end_valid (w, Qnil);
 
       /* Forget any recorded base line for line number display.  */
       if (!buffer_unchanged_p)
-       WSET (w, base_line_number, Qnil);
+       wset_base_line_number (w, Qnil);
 
       /* Redisplay the mode line.  Select the buffer properly for that.
         Also, run the hook window-scroll-functions
@@ -15636,6 +15650,34 @@ 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)
+       {
+         /* Some people insist on not letting point enter the scroll
+            margin, even though this part handles windows that didn't
+            scroll at all.  */
+         int margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+         int pixel_margin = margin * FRAME_LINE_HEIGHT (f);
+         bool header_line = WINDOW_WANTS_HEADER_LINE_P (w);
+
+         /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop
+            below, which finds the row to move point to, advances by
+            the Y coordinate of the _next_ row, see the definition of
+            MATRIX_ROW_BOTTOM_Y.  */
+         if (w->cursor.vpos < margin + header_line)
+           new_vpos
+             = pixel_margin + (header_line
+                               ? CURRENT_HEADER_LINE_HEIGHT (w)
+                               : 0) + FRAME_LINE_HEIGHT (f);
+         else
+           {
+             int window_height = window_box_height (w);
+
+             if (header_line)
+               window_height += CURRENT_HEADER_LINE_HEIGHT (w);
+             if (w->cursor.y >= window_height - pixel_margin)
+               new_vpos = window_height - pixel_margin;
+           }
+       }
 
       /* If we need to move point for either of the above reasons,
         now actually do it.  */
@@ -15651,7 +15693,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
                            MATRIX_ROW_START_BYTEPOS (row));
 
          if (w != XWINDOW (selected_window))
-           set_marker_both (WGET (w, pointm), Qnil, PT, PT_BYTE);
+           set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
          else if (current_buffer == old)
            SET_TEXT_POS (lpoint, PT, PT_BYTE);
 
@@ -15659,8 +15701,7 @@ 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 (!NILP (Vtransient_mark_mode)
-             && !NILP (BVAR (current_buffer, mark_active)))
+         if (0 <= markpos_of_region ())
            {
              clear_glyph_matrix (w->desired_matrix);
              if (!try_window (window, startp, 0))
@@ -15691,7 +15732,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          goto try_to_scroll;
 
        default:
-         abort ();
+         emacs_abort ();
        }
     }
   /* If current starting point was originally the beginning of a line
@@ -15729,8 +15770,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
           && (CHARPOS (startp) < ZV
               /* Avoid starting at end of buffer.  */
               || CHARPOS (startp) == BEGV
-              || (w->last_modified >= MODIFF
-                  && w->last_overlay_modified >= OVERLAY_MODIFF)))
+              || !window_outdated (w)))
     {
       int d1, d2, d3, d4, d5, d6;
 
@@ -15753,7 +15793,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
             sets it.  So, we need to check the return value of
             compute_window_start_on_continuation_line.  (See also
             bug#197).  */
-         && XMARKER (WGET (w, start))->buffer == current_buffer
+         && XMARKER (w->start)->buffer == current_buffer
          && compute_window_start_on_continuation_line (w)
          /* It doesn't make sense to force the window start like we
             do at label force_start if it is already known that point
@@ -15764,7 +15804,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          && pos_visible_p (w, PT, &d1, &d2, &d3, &d4, &d5, &d6))
        {
          w->force_start = 1;
-         SET_TEXT_POS_FROM_MARKER (startp, WGET (w, start));
+         SET_TEXT_POS_FROM_MARKER (startp, w->start);
          goto force_start;
        }
 
@@ -15800,7 +15840,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              || current_buffer->clip_changed
              || BEG_UNCHANGED < CHARPOS (startp))
            /* Forget any recorded base line for line number display.  */
-           WSET (w, base_line_number, Qnil);
+           wset_base_line_number (w, Qnil);
 
          if (!cursor_row_fully_visible_p (w, 1, 0))
            {
@@ -15854,7 +15894,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          break;
 
        default:
-         abort ();
+         emacs_abort ();
        }
     }
 
@@ -15871,7 +15911,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
   /* Forget any previously recorded base line for line number display.  */
   if (!buffer_unchanged_p)
-    WSET (w, base_line_number, Qnil);
+    wset_base_line_number (w, Qnil);
 
   /* Determine the window start relative to point.  */
   init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
@@ -15974,7 +16014,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   /* Set the window start position here explicitly, to avoid an
      infinite loop in case the functions in window-scroll-functions
      get errors.  */
-  set_marker_both (WGET (w, start), Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
+  set_marker_both (w->start, Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
 
   /* Run scroll hooks.  */
   startp = run_window_scroll_functions (window, it.current.pos);
@@ -16005,8 +16045,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
      line.)  */
   if (w->cursor.vpos < 0)
     {
-      if (!NILP (WGET (w, window_end_valid))
-         && PT >= Z - XFASTINT (WGET (w, window_end_pos)))
+      if (!NILP (w->window_end_valid)
+         && PT >= Z - XFASTINT (w->window_end_pos))
        {
          clear_glyph_matrix (w->desired_matrix);
          move_it_by_lines (&it, 1);
@@ -16078,7 +16118,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
  done:
 
-  SET_TEXT_POS_FROM_MARKER (startp, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (startp, w->start);
   w->start_at_line_beg = (CHARPOS (startp) == BEGV
                            || FETCH_BYTE (BYTEPOS (startp) - 1) == '\n');
 
@@ -16092,10 +16132,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
           && !FRAME_WINDOW_P (f)
           && !WINDOW_FULL_WIDTH_P (w))
        /* Line number to display.  */
-       || INTEGERP (WGET (w, base_line_pos))
+       || INTEGERP (w->base_line_pos)
        /* Column number is displayed and different from the one displayed.  */
-       || (!NILP (WGET (w, column_number_displayed))
-          && (XFASTINT (WGET (w, column_number_displayed)) != current_column ())))
+       || (!NILP (w->column_number_displayed)
+          && (XFASTINT (w->column_number_displayed) != current_column ())))
       /* This means that the window has a mode line.  */
       && (WINDOW_WANTS_MODELINE_P (w)
          || WINDOW_WANTS_HEADER_LINE_P (w)))
@@ -16127,10 +16167,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
     }
 
   if (!line_number_displayed
-      && !BUFFERP (WGET (w, base_line_pos)))
+      && !BUFFERP (w->base_line_pos))
     {
-      WSET (w, base_line_pos, Qnil);
-      WSET (w, base_line_number, Qnil);
+      wset_base_line_pos (w, Qnil);
+      wset_base_line_number (w, Qnil);
     }
 
  finish_menu_bars:
@@ -16163,7 +16203,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          if (FRAME_EXTERNAL_TOOL_BAR (f))
            redisplay_tool_bar (f);
 #else
-         if (WINDOWP (FGET (f, tool_bar_window))
+         if (WINDOWP (f->tool_bar_window)
              && (FRAME_TOOL_BAR_LINES (f) > 0
                  || !NILP (Vauto_resize_tool_bars))
              && redisplay_tool_bar (f))
@@ -16180,15 +16220,15 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
                                    || w->pseudo_window_p)))
     {
       update_begin (f);
-      BLOCK_INPUT;
+      block_input ();
       if (draw_window_fringes (w, 1))
        x_draw_vertical_border (w);
-      UNBLOCK_INPUT;
+      unblock_input ();
       update_end (f);
     }
 #endif /* HAVE_WINDOW_SYSTEM */
 
-  /* We go to this label, with fonts_changed_p nonzero,
+  /* We go to this label, with fonts_changed_p set,
      if it is necessary to try again using larger glyph matrices.
      We have to redeem the scroll bar even in this case,
      because the loop in redisplay_internal expects that.  */
@@ -16243,10 +16283,10 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
   struct window *w = XWINDOW (window);
   struct it it;
   struct glyph_row *last_text_row = NULL;
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
 
   /* Make POS the new window start.  */
-  set_marker_both (WGET (w, start), Qnil, CHARPOS (pos), BYTEPOS (pos));
+  set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos));
 
   /* Mark cursor position as unknown.  No overlay arrow seen.  */
   w->cursor.vpos = -1;
@@ -16295,7 +16335,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
     }
 
   /* If bottom moved off end of frame, change mode line percentage.  */
-  if (XFASTINT (WGET (w, window_end_pos)) <= 0
+  if (XFASTINT (w->window_end_pos) <= 0
       && Z != IT_CHARPOS (it))
     w->update_mode_line = 1;
 
@@ -16307,23 +16347,23 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
       eassert (MATRIX_ROW_DISPLAYS_TEXT_P (last_text_row));
       w->window_end_bytepos
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-      WSET (w, window_end_pos,
-           make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-      WSET (w, window_end_vpos,
-           make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix)));
+      wset_window_end_pos
+       (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
+      wset_window_end_vpos
+       (w, make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix)));
       eassert
        (MATRIX_ROW (w->desired_matrix,
-                    XFASTINT (WGET (w, window_end_vpos)))->displays_text_p);
+                    XFASTINT (w->window_end_vpos))->displays_text_p);
     }
   else
     {
       w->window_end_bytepos = Z_BYTE - ZV_BYTE;
-      WSET (w, window_end_pos, make_number (Z - ZV));
-      WSET (w, window_end_vpos, make_number (0));
+      wset_window_end_pos (w, make_number (Z - ZV));
+      wset_window_end_vpos (w, make_number (0));
     }
 
   /* But that is not valid info until redisplay finishes.  */
-  WSET (w, window_end_valid, Qnil);
+  wset_window_end_valid (w, Qnil);
   return 1;
 }
 
@@ -16341,7 +16381,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
 static int
 try_window_reusing_current_matrix (struct window *w)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   struct glyph_row *bottom_row;
   struct it it;
   struct run run;
@@ -16366,9 +16406,8 @@ try_window_reusing_current_matrix (struct window *w)
     return 0;
 
   /* Can't do this if region may have changed.  */
-  if ((!NILP (Vtransient_mark_mode)
-       && !NILP (BVAR (current_buffer, mark_active)))
-      || !NILP (WGET (w, region_showing))
+  if (0 <= markpos_of_region ()
+      || !NILP (w->region_showing)
       || !NILP (Vshow_trailing_whitespace))
     return 0;
 
@@ -16385,7 +16424,7 @@ try_window_reusing_current_matrix (struct window *w)
 
   /* The variable new_start now holds the new window start.  The old
      start `start' can be determined from the current matrix.  */
-  SET_TEXT_POS_FROM_MARKER (new_start, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (new_start, w->start);
   start = start_row->minpos;
   start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
 
@@ -16547,28 +16586,31 @@ try_window_reusing_current_matrix (struct window *w)
        {
          w->window_end_bytepos
            = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_reused_text_row);
-         WSET (w, window_end_pos,
-               make_number (Z - MATRIX_ROW_END_CHARPOS (last_reused_text_row)));
-         WSET (w, window_end_vpos,
-               make_number (MATRIX_ROW_VPOS (last_reused_text_row, w->current_matrix)));
+         wset_window_end_pos
+           (w, make_number (Z
+                            - MATRIX_ROW_END_CHARPOS (last_reused_text_row)));
+         wset_window_end_vpos
+           (w, make_number (MATRIX_ROW_VPOS (last_reused_text_row,
+                                             w->current_matrix)));
        }
       else if (last_text_row)
        {
          w->window_end_bytepos
            = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-         WSET (w, window_end_pos,
-               make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-         WSET (w, window_end_vpos,
-               make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix)));
+         wset_window_end_pos
+           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
+         wset_window_end_vpos
+           (w, make_number (MATRIX_ROW_VPOS (last_text_row,
+                                             w->desired_matrix)));
        }
       else
        {
          /* This window must be completely empty.  */
          w->window_end_bytepos = Z_BYTE - ZV_BYTE;
-         WSET (w, window_end_pos, make_number (Z - ZV));
-         WSET (w, window_end_vpos, make_number (0));
+         wset_window_end_pos (w, make_number (Z - ZV));
+         wset_window_end_vpos (w, make_number (0));
        }
-      WSET (w, window_end_valid, Qnil);
+      wset_window_end_valid (w, Qnil);
 
       /* Update hint: don't try scrolling again in update_window.  */
       w->desired_matrix->no_scrolling_p = 1;
@@ -16717,28 +16759,33 @@ try_window_reusing_current_matrix (struct window *w)
            }
          if (row < bottom_row)
            {
-             struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
-             struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
-
-             /* Can't use this optimization with bidi-reordered glyph
-                rows, unless cursor is already at point. */
-             if (!NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering)))
+             /* Can't simply scan the row for point with
+                bidi-reordered glyph rows.  Let set_cursor_from_row
+                figure out where to put the cursor, and if it fails,
+                give up.  */
+             if (!NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering)))
                {
-                 if (!(w->cursor.hpos >= 0
-                       && w->cursor.hpos < row->used[TEXT_AREA]
-                       && BUFFERP (glyph->object)
-                       && glyph->charpos == PT))
-                   return 0;
+                 if (!set_cursor_from_row (w, row, w->current_matrix,
+                                           0, 0, 0, 0))
+                   {
+                     clear_glyph_matrix (w->desired_matrix);
+                     return 0;
+                   }
                }
              else
-               for (; glyph < end
-                      && (!BUFFERP (glyph->object)
-                          || glyph->charpos < PT);
-                    glyph++)
-                 {
-                   w->cursor.hpos++;
-                   w->cursor.x += glyph->pixel_width;
-                 }
+               {
+                 struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
+                 struct glyph *end = row->glyphs[TEXT_AREA] + row->used[TEXT_AREA];
+
+                 for (; glyph < end
+                        && (!BUFFERP (glyph->object)
+                            || glyph->charpos < PT);
+                      glyph++)
+                   {
+                     w->cursor.hpos++;
+                     w->cursor.x += glyph->pixel_width;
+                   }
+               }
            }
        }
 
@@ -16749,18 +16796,19 @@ try_window_reusing_current_matrix (struct window *w)
        {
          w->window_end_bytepos
            = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-         WSET (w, window_end_pos,
-               make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
-         WSET (w, window_end_vpos,
-               make_number (MATRIX_ROW_VPOS (last_text_row, w->desired_matrix)));
+         wset_window_end_pos
+           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
+         wset_window_end_vpos
+           (w, make_number (MATRIX_ROW_VPOS (last_text_row,
+                                             w->desired_matrix)));
        }
       else
        {
-         WSET (w, window_end_vpos,
-               make_number (XFASTINT (WGET (w, window_end_vpos)) - nrows_scrolled));
+         wset_window_end_vpos
+           (w, make_number (XFASTINT (w->window_end_vpos) - nrows_scrolled));
        }
 
-      WSET (w, window_end_valid, Qnil);
+      wset_window_end_valid (w, Qnil);
       w->desired_matrix->no_scrolling_p = 1;
 
 #ifdef GLYPH_DEBUG
@@ -16893,16 +16941,16 @@ find_first_unchanged_at_end_row (struct window *w,
 
   /* Display must not have been paused, otherwise the current matrix
      is not up to date.  */
-  eassert (!NILP (WGET (w, window_end_valid)));
+  eassert (!NILP (w->window_end_valid));
 
   /* A value of window_end_pos >= END_UNCHANGED means that the window
      end is in the range of changed text.  If so, there is no
      unchanged row at the end of W's current matrix.  */
-  if (XFASTINT (WGET (w, window_end_pos)) >= END_UNCHANGED)
+  if (XFASTINT (w->window_end_pos) >= END_UNCHANGED)
     return NULL;
 
   /* Set row to the last row in W's current matrix displaying text.  */
-  row = MATRIX_ROW (w->current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+  row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
 
   /* If matrix is entirely empty, no unchanged row exists.  */
   if (MATRIX_ROW_DISPLAYS_TEXT_P (row))
@@ -16913,7 +16961,7 @@ find_first_unchanged_at_end_row (struct window *w,
         buffer positions in the current matrix to current buffer
         positions for characters not in changed text.  */
       ptrdiff_t Z_old =
-       MATRIX_ROW_END_CHARPOS (row) + XFASTINT (WGET (w, window_end_pos));
+       MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
       ptrdiff_t Z_BYTE_old =
        MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
       ptrdiff_t last_unchanged_pos, last_unchanged_pos_old;
@@ -16961,12 +17009,12 @@ find_first_unchanged_at_end_row (struct window *w,
 static void
 sync_frame_with_window_matrix_rows (struct window *w)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   struct glyph_row *window_row, *window_row_end, *frame_row;
 
   /* Preconditions: W must be a leaf window and full-width.  Its frame
      must have a frame matrix.  */
-  eassert (NILP (WGET (w, hchild)) && NILP (WGET (w, vchild)));
+  eassert (NILP (w->hchild) && NILP (w->vchild));
   eassert (WINDOW_FULL_WIDTH_P (w));
   eassert (!FRAME_WINDOW_P (f));
 
@@ -17008,7 +17056,7 @@ row_containing_pos (struct window *w, ptrdiff_t charpos,
 {
   struct glyph_row *row = start;
   struct glyph_row *best_row = NULL;
-  ptrdiff_t mindif = BUF_ZV (XBUFFER (WGET (w, buffer))) + 1;
+  ptrdiff_t mindif = BUF_ZV (XBUFFER (w->buffer)) + 1;
   int last_y;
 
   /* If we happen to start on a header-line, skip that.  */
@@ -17044,7 +17092,7 @@ row_containing_pos (struct window *w, ptrdiff_t charpos,
        {
          struct glyph *g;
 
-         if (NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering))
+         if (NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering))
              || (!best_row && !row->continued_p))
            return row;
          /* In bidi-reordered rows, there could be several rows
@@ -17113,7 +17161,7 @@ row_containing_pos (struct window *w, ptrdiff_t charpos,
 static int
 try_window_id (struct window *w)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   struct glyph_matrix *current_matrix = w->current_matrix;
   struct glyph_matrix *desired_matrix = w->desired_matrix;
   struct glyph_row *last_unchanged_at_beg_row;
@@ -17147,7 +17195,7 @@ try_window_id (struct window *w)
 #define GIVE_UP(X) return 0
 #endif
 
-  SET_TEXT_POS_FROM_MARKER (start, WGET (w, start));
+  SET_TEXT_POS_FROM_MARKER (start, w->start);
 
   /* Don't use this for mini-windows because these can show
      messages and mini-buffers, and we don't handle that here.  */
@@ -17185,13 +17233,12 @@ try_window_id (struct window *w)
     GIVE_UP (7);
 
   /* Verify that display wasn't paused.  */
-  if (NILP (WGET (w, window_end_valid)))
+  if (NILP (w->window_end_valid))
     GIVE_UP (8);
 
   /* Can't use this if highlighting a region because a cursor movement
      will do more than just set the cursor.  */
-  if (!NILP (Vtransient_mark_mode)
-      && !NILP (BVAR (current_buffer, mark_active)))
+  if (0 <= markpos_of_region ())
     GIVE_UP (9);
 
   /* Likewise if highlighting trailing whitespace.  */
@@ -17199,7 +17246,7 @@ try_window_id (struct window *w)
     GIVE_UP (11);
 
   /* Likewise if showing a region.  */
-  if (!NILP (WGET (w, region_showing)))
+  if (!NILP (w->region_showing))
     GIVE_UP (10);
 
   /* Can't use this if overlay arrow position and/or string have
@@ -17211,7 +17258,7 @@ try_window_id (struct window *w)
      wrapped line can change the wrap position, altering the line
      above it.  It might be worthwhile to handle this more
      intelligently, but for now just redisplay from scratch.  */
-  if (!NILP (BVAR (XBUFFER (WGET (w, buffer)), word_wrap)))
+  if (!NILP (BVAR (XBUFFER (w->buffer), word_wrap)))
     GIVE_UP (21);
 
   /* Under bidi reordering, adding or deleting a character in the
@@ -17222,8 +17269,8 @@ try_window_id (struct window *w)
      to find the paragraph limits and widen the range of redisplayed
      lines to that, but for now just give up this optimization and
      redisplay from scratch.  */
-  if (!NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_display_reordering))
-      && NILP (BVAR (XBUFFER (WGET (w, buffer)), bidi_paragraph_direction)))
+  if (!NILP (BVAR (XBUFFER (w->buffer), bidi_display_reordering))
+      && NILP (BVAR (XBUFFER (w->buffer), bidi_paragraph_direction)))
     GIVE_UP (22);
 
   /* Make sure beg_unchanged and end_unchanged are up to date.  Do it
@@ -17249,7 +17296,7 @@ try_window_id (struct window *w)
      This case happens with stealth-fontification.  Note that although
      the display is unchanged, glyph positions in the matrix have to
      be adjusted, of course.  */
-  row = MATRIX_ROW (w->current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+  row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
   if (MATRIX_ROW_DISPLAYS_TEXT_P (row)
       && ((last_changed_charpos < CHARPOS (start)
           && CHARPOS (start) == BEGV)
@@ -17261,7 +17308,7 @@ try_window_id (struct window *w)
 
       /* Compute how many chars/bytes have been added to or removed
         from the buffer.  */
-      Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (WGET (w, window_end_pos));
+      Z_old = MATRIX_ROW_END_CHARPOS (row) + XFASTINT (w->window_end_pos);
       Z_BYTE_old = MATRIX_ROW_END_BYTEPOS (row) + w->window_end_bytepos;
       Z_delta = Z - Z_old;
       Z_delta_bytes = Z_BYTE - Z_BYTE_old;
@@ -17298,7 +17345,7 @@ try_window_id (struct window *w)
          if (row)
            set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
          else
-           abort ();
+           emacs_abort ();
          return 1;
        }
     }
@@ -17332,8 +17379,8 @@ try_window_id (struct window *w)
        {
          /* We have to compute the window end anew since text
             could have been added/removed after it.  */
-         WSET (w, window_end_pos,
-               make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
+         wset_window_end_pos
+           (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
          w->window_end_bytepos
            = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
 
@@ -17342,7 +17389,7 @@ try_window_id (struct window *w)
          if (row)
            set_cursor_from_row (w, row, current_matrix, 0, 0, 0, 0);
          else
-           abort ();
+           emacs_abort ();
          return 2;
        }
     }
@@ -17368,7 +17415,7 @@ try_window_id (struct window *w)
 
   /* Give up if the window ends in strings.  Overlay strings
      at the end are difficult to handle, so don't try.  */
-  row = MATRIX_ROW (current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+  row = MATRIX_ROW (current_matrix, XFASTINT (w->window_end_vpos));
   if (MATRIX_ROW_START_CHARPOS (row) == MATRIX_ROW_END_CHARPOS (row))
     GIVE_UP (20);
 
@@ -17665,15 +17712,15 @@ try_window_id (struct window *w)
     {
       rotate_matrix (current_matrix, first_unchanged_at_end_vpos + dvpos,
                     bottom_vpos, dvpos);
-      enable_glyph_matrix_rows (current_matrix, bottom_vpos + dvpos,
-                               bottom_vpos, 0);
+      clear_glyph_matrix_rows (current_matrix, bottom_vpos + dvpos,
+                              bottom_vpos);
     }
   else if (dvpos > 0)
     {
       rotate_matrix (current_matrix, first_unchanged_at_end_vpos,
                     bottom_vpos, dvpos);
-      enable_glyph_matrix_rows (current_matrix, first_unchanged_at_end_vpos,
-                               first_unchanged_at_end_vpos + dvpos, 0);
+      clear_glyph_matrix_rows (current_matrix, first_unchanged_at_end_vpos,
+                              first_unchanged_at_end_vpos + dvpos);
     }
 
   /* For frame-based redisplay, make sure that current frame and window
@@ -17711,7 +17758,7 @@ try_window_id (struct window *w)
       /* Set last_row to the glyph row in the current matrix where the
         window end line is found.  It has been moved up or down in
         the matrix by dvpos.  */
-      int last_vpos = XFASTINT (WGET (w, window_end_vpos)) + dvpos;
+      int last_vpos = XFASTINT (w->window_end_vpos) + dvpos;
       struct glyph_row *last_row = MATRIX_ROW (current_matrix, last_vpos);
 
       /* If last_row is the window end line, it should display text.  */
@@ -17767,21 +17814,22 @@ try_window_id (struct window *w)
                                           first_unchanged_at_end_row);
       eassert (row && MATRIX_ROW_DISPLAYS_TEXT_P (row));
 
-      WSET (w, window_end_pos, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
+      wset_window_end_pos (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
-      WSET (w, window_end_vpos,
-           make_number (MATRIX_ROW_VPOS (row, w->current_matrix)));
+      wset_window_end_vpos
+       (w, make_number (MATRIX_ROW_VPOS (row, w->current_matrix)));
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "A"));
     }
   else if (last_text_row_at_end)
     {
-      WSET (w, window_end_pos,
-           make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row_at_end)));
+      wset_window_end_pos
+       (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row_at_end)));
       w->window_end_bytepos
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row_at_end);
-      WSET (w, window_end_vpos,
-           make_number (MATRIX_ROW_VPOS (last_text_row_at_end, desired_matrix)));
+      wset_window_end_vpos
+       (w, make_number (MATRIX_ROW_VPOS (last_text_row_at_end,
+                                         desired_matrix)));
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "B"));
     }
@@ -17790,12 +17838,12 @@ try_window_id (struct window *w)
       /* We have displayed either to the end of the window or at the
         end of the window, i.e. the last row with text is to be found
         in the desired matrix.  */
-      WSET (w, window_end_pos,
-           make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
+      wset_window_end_pos
+       (w, make_number (Z - MATRIX_ROW_END_CHARPOS (last_text_row)));
       w->window_end_bytepos
        = Z_BYTE - MATRIX_ROW_END_BYTEPOS (last_text_row);
-      WSET (w, window_end_vpos,
-           make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix)));
+      wset_window_end_vpos
+       (w, make_number (MATRIX_ROW_VPOS (last_text_row, desired_matrix)));
       eassert (w->window_end_bytepos >= 0);
     }
   else if (first_unchanged_at_end_row == NULL
@@ -17805,7 +17853,7 @@ try_window_id (struct window *w)
       /* Displayed to end of window, but no line containing text was
         displayed.  Lines were deleted at the end of the window.  */
       int first_vpos = WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0;
-      int vpos = XFASTINT (WGET (w, window_end_vpos));
+      int vpos = XFASTINT (w->window_end_vpos);
       struct glyph_row *current_row = current_matrix->rows + vpos;
       struct glyph_row *desired_row = desired_matrix->rows + vpos;
 
@@ -17823,20 +17871,20 @@ try_window_id (struct window *w)
        }
 
       eassert (row != NULL);
-      WSET (w, window_end_vpos, make_number (vpos + 1));
-      WSET (w, window_end_pos, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
+      wset_window_end_vpos (w, make_number (vpos + 1));
+      wset_window_end_pos (w, make_number (Z - MATRIX_ROW_END_CHARPOS (row)));
       w->window_end_bytepos = Z_BYTE - MATRIX_ROW_END_BYTEPOS (row);
       eassert (w->window_end_bytepos >= 0);
       IF_DEBUG (debug_method_add (w, "C"));
     }
   else
-    abort ();
+    emacs_abort ();
 
-  IF_DEBUG (debug_end_pos = XFASTINT (WGET (w, window_end_pos));
-           debug_end_vpos = XFASTINT (WGET (w, window_end_vpos)));
+  IF_DEBUG (debug_end_pos = XFASTINT (w->window_end_pos);
+           debug_end_vpos = XFASTINT (w->window_end_vpos));
 
   /* Record that display has not been completed.  */
-  WSET (w, window_end_valid, Qnil);
+  wset_window_end_valid (w, Qnil);
   w->desired_matrix->no_scrolling_p = 1;
   return 3;
 
@@ -18066,7 +18114,7 @@ glyphs in short form, otherwise show glyphs in long form.  */)
   (Lisp_Object glyphs)
 {
   struct window *w = XWINDOW (selected_window);
-  struct buffer *buffer = XBUFFER (WGET (w, buffer));
+  struct buffer *buffer = XBUFFER (w->buffer);
 
   fprintf (stderr, "PT = %"pI"d, BEGV = %"pI"d. ZV = %"pI"d\n",
           BUF_PT (buffer), BUF_BEGV (buffer), BUF_ZV (buffer));
@@ -18118,7 +18166,7 @@ GLYPH > 1 or omitted means dump glyphs in long form.  */)
   (Lisp_Object row, Lisp_Object glyphs)
 {
   struct frame *sf = SELECTED_FRAME ();
-  struct glyph_matrix *m = XWINDOW (FGET (sf, tool_bar_window))->current_matrix;
+  struct glyph_matrix *m = XWINDOW (sf->tool_bar_window)->current_matrix;
   EMACS_INT vpos;
 
   CHECK_NUMBER (row);
@@ -18172,7 +18220,7 @@ static struct glyph_row *
 get_overlay_arrow_glyph_row (struct window *w, Lisp_Object overlay_arrow_string)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  struct buffer *buffer = XBUFFER (WGET (w, buffer));
+  struct buffer *buffer = XBUFFER (w->buffer);
   struct buffer *old = current_buffer;
   const unsigned char *arrow_string = SDATA (overlay_arrow_string);
   int arrow_len = SCHARS (overlay_arrow_string);
@@ -18523,6 +18571,7 @@ append_space_for_newline (struct it *it, int default_face_p)
          int saved_char_to_display = it->char_to_display;
          int saved_x = it->current_x;
          int saved_face_id = it->face_id;
+         int saved_box_end = it->end_of_box_run_p;
          struct text_pos saved_pos;
          Lisp_Object saved_object;
          struct face *face;
@@ -18544,6 +18593,16 @@ append_space_for_newline (struct it *it, int default_face_p)
            it->face_id = it->saved_face_id;
          face = FACE_FROM_ID (it->f, it->face_id);
          it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil);
+         /* In R2L rows, we will prepend a stretch glyph that will
+            have the end_of_box_run_p flag set for it, so there's no
+            need for the appended newline glyph to have that flag
+            set.  */
+         if (it->glyph_row->reversed_p
+             /* But if the appended newline glyph goes all the way to
+                the end of the row, there will be no stretch glyph,
+                so leave the box flag set.  */
+             && saved_x + FRAME_COLUMN_WIDTH (it->f) < it->last_visible_x)
+           it->end_of_box_run_p = 0;
 
          PRODUCE_GLYPHS (it);
 
@@ -18557,6 +18616,7 @@ append_space_for_newline (struct it *it, int default_face_p)
          it->len = saved_len;
          it->c = saved_c;
          it->char_to_display = saved_char_to_display;
+         it->end_of_box_run_p = saved_box_end;
          return 1;
        }
     }
@@ -18646,7 +18706,7 @@ extend_face_to_end_of_line (struct it *it)
          struct glyph *g;
          int row_width, stretch_ascent, stretch_width;
          struct text_pos saved_pos;
-         int saved_face_id, saved_avoid_cursor;
+         int saved_face_id, saved_avoid_cursor, saved_box_start;
 
          for (row_width = 0, g = row_start; g < row_end; g++)
            row_width += g->pixel_width;
@@ -18661,6 +18721,7 @@ extend_face_to_end_of_line (struct it *it)
              saved_avoid_cursor = it->avoid_cursor_p;
              it->avoid_cursor_p = 1;
              saved_face_id = it->face_id;
+             saved_box_start = it->start_of_box_run_p;
              /* The last row's stretch glyph should get the default
                 face, to avoid painting the rest of the window with
                 the region face, if the region ends at ZV.  */
@@ -18668,11 +18729,13 @@ extend_face_to_end_of_line (struct it *it)
                it->face_id = default_face->id;
              else
                it->face_id = face->id;
+             it->start_of_box_run_p = 0;
              append_stretch_glyph (it, make_number (0), stretch_width,
                                    it->ascent + it->descent, stretch_ascent);
              it->position = saved_pos;
              it->avoid_cursor_p = saved_avoid_cursor;
              it->face_id = saved_face_id;
+             it->start_of_box_run_p = saved_box_start;
            }
        }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -19207,7 +19270,7 @@ find_row_edges (struct it *it, struct glyph_row *row,
        /* A line that is entirely from a string/image/stretch...  */
        row->maxpos = row->minpos;
       else
-       abort ();
+       emacs_abort ();
     }
   else
     row->maxpos = it->current.pos;
@@ -19249,7 +19312,7 @@ display_line (struct it *it)
     }
 
   /* Is IT->w showing the region?  */
-  WSET (it->w, region_showing, it->region_beg_charpos > 0 ? Qt : Qnil);
+  wset_region_showing (it->w, it->region_beg_charpos > 0 ? Qt : Qnil);
 
   /* Clear the result glyph row and enable it.  */
   prepare_desired_row (row);
@@ -19364,7 +19427,7 @@ display_line (struct it *it)
              row->glyphs[TEXT_AREA]->charpos = -1;
              row->displays_text_p = 0;
 
-             if (!NILP (BVAR (XBUFFER (WGET (it->w, buffer)), indicate_empty_lines))
+             if (!NILP (BVAR (XBUFFER (it->w->buffer), indicate_empty_lines))
                  && (!MINI_WINDOW_P (it->w)
                      || (minibuf_level && EQ (it->window, minibuf_window))))
                row->indicate_empty_line_p = 1;
@@ -20048,7 +20111,7 @@ See also `bidi-paragraph-direction'.  */)
          return Qright_to_left;
          break;
        default:
-         abort ();
+         emacs_abort ();
        }
     }
 }
@@ -20103,8 +20166,8 @@ display_menu_bar (struct window *w)
       /* Menu bar lines are displayed in the desired matrix of the
         dummy window menu_bar_window.  */
       struct window *menu_w;
-      eassert (WINDOWP (FGET (f, menu_bar_window)));
-      menu_w = XWINDOW (FGET (f, menu_bar_window));
+      eassert (WINDOWP (f->menu_bar_window));
+      menu_w = XWINDOW (f->menu_bar_window);
       init_iterator (&it, menu_w, -1, -1, menu_w->desired_matrix->rows,
                     MENU_FACE_ID);
       it.first_visible_x = 0;
@@ -20126,10 +20189,6 @@ display_menu_bar (struct window *w)
      this.  */
   it.paragraph_embedding = L2R;
 
-  if (! mode_line_inverse_video)
-    /* Force the menu-bar to be displayed in the default face.  */
-    it.base_face_id = it.face_id = DEFAULT_FACE_ID;
-
   /* Clear all rows of the menu bar.  */
   for (i = 0; i < FRAME_MENU_BAR_LINES (f); ++i)
     {
@@ -20187,12 +20246,12 @@ redisplay_mode_lines (Lisp_Object window, int force)
     {
       struct window *w = XWINDOW (window);
 
-      if (WINDOWP (WGET (w, hchild)))
-       nwindows += redisplay_mode_lines (WGET (w, hchild), force);
-      else if (WINDOWP (WGET (w, vchild)))
-       nwindows += redisplay_mode_lines (WGET (w, vchild), force);
+      if (WINDOWP (w->hchild))
+       nwindows += redisplay_mode_lines (w->hchild, force);
+      else if (WINDOWP (w->vchild))
+       nwindows += redisplay_mode_lines (w->vchild, force);
       else if (force
-              || FRAME_GARBAGED_P (XFRAME (WGET (w, frame)))
+              || FRAME_GARBAGED_P (XFRAME (w->frame))
               || !MATRIX_MODE_LINE_ROW (w->current_matrix)->enabled_p)
        {
          struct text_pos lpoint;
@@ -20200,7 +20259,7 @@ redisplay_mode_lines (Lisp_Object window, int force)
 
          /* Set the window's buffer for the mode line display.  */
          SET_TEXT_POS (lpoint, PT, PT_BYTE);
-         set_buffer_internal_1 (XBUFFER (WGET (w, buffer)));
+         set_buffer_internal_1 (XBUFFER (w->buffer));
 
          /* Point refers normally to the selected window.  For any
             other window, set up appropriate value.  */
@@ -20208,7 +20267,7 @@ redisplay_mode_lines (Lisp_Object window, int force)
            {
              struct text_pos pt;
 
-             SET_TEXT_POS_FROM_MARKER (pt, WGET (w, pointm));
+             SET_TEXT_POS_FROM_MARKER (pt, w->pointm);
              if (CHARPOS (pt) < BEGV)
                TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
              else if (CHARPOS (pt) > (ZV - 1))
@@ -20230,7 +20289,7 @@ redisplay_mode_lines (Lisp_Object window, int force)
          TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
        }
 
-      window = WGET (w, next);
+      window = w->next;
     }
 
   return nwindows;
@@ -20243,17 +20302,21 @@ redisplay_mode_lines (Lisp_Object window, int force)
 static int
 display_mode_lines (struct window *w)
 {
-  Lisp_Object old_selected_window, old_selected_frame;
+  Lisp_Object old_selected_window = selected_window;
+  Lisp_Object old_selected_frame = selected_frame;
+  Lisp_Object new_frame = w->frame;
+  Lisp_Object old_frame_selected_window = XFRAME (new_frame)->selected_window;
   int n = 0;
 
-  old_selected_frame = selected_frame;
-  selected_frame = WGET (w, frame);
-  old_selected_window = selected_window;
+  selected_frame = new_frame;
+  /* FIXME: If we were to allow the mode-line's computation changing the buffer
+     or window's point, then we'd need select_window_1 here as well.  */
   XSETWINDOW (selected_window, w);
+  XFRAME (new_frame)->selected_window = selected_window;
 
   /* These will be set while the mode line specs are processed.  */
   line_number_displayed = 0;
-  WSET (w, column_number_displayed, Qnil);
+  wset_column_number_displayed (w, Qnil);
 
   if (WINDOW_WANTS_MODELINE_P (w))
     {
@@ -20272,6 +20335,7 @@ display_mode_lines (struct window *w)
       ++n;
     }
 
+  XFRAME (new_frame)->selected_window = old_frame_selected_window;
   selected_frame = old_selected_frame;
   selected_window = old_selected_window;
   return n;
@@ -20299,10 +20363,6 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
 
   it.glyph_row->mode_line_p = 1;
 
-  if (! mode_line_inverse_video)
-    /* Force the mode-line to be displayed in the default face.  */
-    it.base_face_id = it.face_id = DEFAULT_FACE_ID;
-
   /* FIXME: This should be controlled by a user option.  But
      supporting such an option is not trivial, since the mode line is
      made up of many separate strings.  */
@@ -20977,13 +21037,11 @@ are the selected window and the WINDOW's buffer).  */)
   Lisp_Object str;
   int string_start = 0;
 
-  if (NILP (window))
-    window = selected_window;
-  CHECK_WINDOW (window);
-  w = XWINDOW (window);
+  w = decode_any_window (window);
+  XSETWINDOW (window, w);
 
   if (NILP (buffer))
-    buffer = WGET (w, buffer);
+    buffer = w->buffer;
   CHECK_BUFFER (buffer);
 
   /* Make formatting the modeline a non-op when noninteractive, otherwise
@@ -21003,20 +21061,18 @@ are the selected window and the WINDOW's buffer).  */)
     : EQ (face, Qtool_bar) ? TOOL_BAR_FACE_ID
     : DEFAULT_FACE_ID;
 
-  if (XBUFFER (buffer) != current_buffer)
-    old_buffer = current_buffer;
+  old_buffer = current_buffer;
 
   /* Save things including mode_line_proptrans_alist,
      and set that to nil so that we don't alter the outer value.  */
   record_unwind_protect (unwind_format_mode_line,
                         format_mode_line_unwind_data
-                          (XFRAME (WINDOW_FRAME (XWINDOW (window))),
+                          (XFRAME (WINDOW_FRAME (w)),
                            old_buffer, selected_window, 1));
   mode_line_proptrans_alist = Qnil;
 
   Fselect_window (window, Qt);
-  if (old_buffer)
-    set_buffer_internal_1 (XBUFFER (buffer));
+  set_buffer_internal_1 (XBUFFER (buffer));
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
 
@@ -21295,6 +21351,12 @@ decode_mode_spec (struct window *w, register int c, int field_width,
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
+  /* We are going to use f->decode_mode_spec_buffer as the buffer to
+     produce strings from numerical values, so limit preposterously
+     large values of FIELD_WIDTH to avoid overrunning the buffer's
+     end.  The size of the buffer is enough for FRAME_MESSAGE_BUF_SIZE
+     bytes plus the terminating null.  */
+  int width = min (field_width, FRAME_MESSAGE_BUF_SIZE (f));
   struct buffer *b = current_buffer;
 
   obj = Qnil;
@@ -21359,8 +21421,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        register int i;
 
        /* Let lots_of_dashes be a string of infinite length.  */
-       if (mode_line_target == MODE_LINE_NOPROP ||
-           mode_line_target == MODE_LINE_STRING)
+       if (mode_line_target == MODE_LINE_NOPROP
+           || mode_line_target == MODE_LINE_STRING)
          return "--";
        if (field_width <= 0
            || field_width > sizeof (lots_of_dashes))
@@ -21389,8 +21451,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
       else
        {
          ptrdiff_t col = current_column ();
-         WSET (w, column_number_displayed, make_number (col));
-         pint2str (decode_mode_spec_buf, field_width, col);
+         wset_column_number_displayed (w, make_number (col));
+         pint2str (decode_mode_spec_buf, width, col);
          return decode_mode_spec_buf;
        }
 
@@ -21408,10 +21470,10 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case 'F':
       /* %F displays the frame name.  */
-      if (!NILP (FGET (f, title)))
-       return SSDATA (FGET (f, title));
+      if (!NILP (f->title))
+       return SSDATA (f->title);
       if (f->explicit_name || ! FRAME_WINDOW_P (f))
-       return SSDATA (FGET (f, name));
+       return SSDATA (f->name);
       return "Emacs";
 
     case 'f':
@@ -21421,14 +21483,14 @@ decode_mode_spec (struct window *w, register int c, int field_width,
     case 'i':
       {
        ptrdiff_t size = ZV - BEGV;
-       pint2str (decode_mode_spec_buf, field_width, size);
+       pint2str (decode_mode_spec_buf, width, size);
        return decode_mode_spec_buf;
       }
 
     case 'I':
       {
        ptrdiff_t size = ZV - BEGV;
-       pint2hrstr (decode_mode_spec_buf, field_width, size);
+       pint2hrstr (decode_mode_spec_buf, width, size);
        return decode_mode_spec_buf;
       }
 
@@ -21442,33 +21504,33 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        if (mode_line_target == MODE_LINE_TITLE)
          return "";
 
-       startpos = XMARKER (WGET (w, start))->charpos;
-       startpos_byte = marker_byte_position (WGET (w, start));
+       startpos = marker_position (w->start);
+       startpos_byte = marker_byte_position (w->start);
        height = WINDOW_TOTAL_LINES (w);
 
        /* If we decided that this buffer isn't suitable for line numbers,
           don't forget that too fast.  */
-       if (EQ (WGET (w, base_line_pos), WGET (w, buffer)))
+       if (EQ (w->base_line_pos, w->buffer))
          goto no_value;
        /* But do forget it, if the window shows a different buffer now.  */
-       else if (BUFFERP (WGET (w, base_line_pos)))
-         WSET (w, base_line_pos, Qnil);
+       else if (BUFFERP (w->base_line_pos))
+         wset_base_line_pos (w, Qnil);
 
        /* If the buffer is very big, don't waste time.  */
        if (INTEGERP (Vline_number_display_limit)
            && BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
          {
-           WSET (w, base_line_pos, Qnil);
-           WSET (w, base_line_number, Qnil);
+           wset_base_line_pos (w, Qnil);
+           wset_base_line_number (w, Qnil);
            goto no_value;
          }
 
-       if (INTEGERP (WGET (w, base_line_number))
-           && INTEGERP (WGET (w, base_line_pos))
-           && XFASTINT (WGET (w, base_line_pos)) <= startpos)
+       if (INTEGERP (w->base_line_number)
+           && INTEGERP (w->base_line_pos)
+           && XFASTINT (w->base_line_pos) <= startpos)
          {
-           line = XFASTINT (WGET (w, base_line_number));
-           linepos = XFASTINT (WGET (w, base_line_pos));
+           line = XFASTINT (w->base_line_number);
+           linepos = XFASTINT (w->base_line_pos);
            linepos_byte = buf_charpos_to_bytepos (b, linepos);
          }
        else
@@ -21491,8 +21553,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
           go back past it.  */
        if (startpos == BUF_BEGV (b))
          {
-           WSET (w, base_line_number, make_number (topline));
-           WSET (w, base_line_pos, make_number (BUF_BEGV (b)));
+           wset_base_line_number (w, make_number (topline));
+           wset_base_line_pos (w, make_number (BUF_BEGV (b)));
          }
        else if (nlines < height + 25 || nlines > height * 3 + 50
                 || linepos == BUF_BEGV (b))
@@ -21518,13 +21580,13 @@ decode_mode_spec (struct window *w, register int c, int field_width,
               give up on line numbers for this window.  */
            if (position == limit_byte && limit == startpos - distance)
              {
-               WSET (w, base_line_pos, WGET (w, buffer));
-               WSET (w, base_line_number, Qnil);
+               wset_base_line_pos (w, w->buffer);
+               wset_base_line_number (w, Qnil);
                goto no_value;
              }
 
-           WSET (w, base_line_number, make_number (topline - nlines));
-           WSET (w, base_line_pos, make_number (BYTE_TO_CHAR (position)));
+           wset_base_line_number (w, make_number (topline - nlines));
+           wset_base_line_pos (w, make_number (BYTE_TO_CHAR (position)));
          }
 
        /* Now count lines from the start pos to point.  */
@@ -21535,12 +21597,12 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        line_number_displayed = 1;
 
        /* Make the string to show.  */
-       pint2str (decode_mode_spec_buf, field_width, topline + nlines);
+       pint2str (decode_mode_spec_buf, width, topline + nlines);
        return decode_mode_spec_buf;
     no_value:
         {
          char* p = decode_mode_spec_buf;
-         int pad = field_width - 2;
+         int pad = width - 2;
          while (pad-- > 0)
            *p++ = ' ';
          *p++ = '?';
@@ -21562,10 +21624,10 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case 'p':
       {
-       ptrdiff_t pos = marker_position (WGET (w, start));
+       ptrdiff_t pos = marker_position (w->start);
        ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
 
-       if (XFASTINT (WGET (w, window_end_pos)) <= BUF_Z (b) - BUF_ZV (b))
+       if (XFASTINT (w->window_end_pos) <= BUF_Z (b) - BUF_ZV (b))
          {
            if (pos <= BUF_BEGV (b))
              return "All";
@@ -21593,8 +21655,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
       /* Display percentage of size above the bottom of the screen.  */
     case 'P':
       {
-       ptrdiff_t toppos = marker_position (WGET (w, start));
-       ptrdiff_t botpos = BUF_Z (b) - XFASTINT (WGET (w, window_end_pos));
+       ptrdiff_t toppos = marker_position (w->start);
+       ptrdiff_t botpos = BUF_Z (b) - XFASTINT (w->window_end_pos);
        ptrdiff_t total = BUF_ZV (b) - BUF_BEGV (b);
 
        if (botpos >= BUF_ZV (b))
@@ -21677,9 +21739,9 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        if (PROCESSP (obj))
          {
            p = decode_mode_spec_coding
-             (PGET (XPROCESS (obj), decode_coding_system), p, eol_flag);
+             (XPROCESS (obj)->decode_coding_system, p, eol_flag);
            p = decode_mode_spec_coding
-             (PGET (XPROCESS (obj), encode_coding_system), p, eol_flag);
+             (XPROCESS (obj)->encode_coding_system, p, eol_flag);
          }
 #endif /* subprocesses */
 #endif /* 0 */
@@ -21961,7 +22023,7 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st
            {
              /* Glyph is off the left margin of the display area.
                 Should not happen.  */
-             abort ();
+             emacs_abort ();
            }
 
          row->ascent = max (row->ascent, it->max_ascent);
@@ -22301,7 +22363,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
            return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
        }
 
-      prop = buffer_local_value_1 (prop, WGET (it->w, buffer));
+      prop = buffer_local_value_1 (prop, it->w->buffer);
       if (EQ (prop, Qunbound))
        prop = Qnil;
     }
@@ -22353,7 +22415,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
              return OK_PIXELS (pixels);
            }
 
-         car = buffer_local_value_1 (car, WGET (it->w, buffer));
+         car = buffer_local_value_1 (car, it->w->buffer);
          if (EQ (car, Qunbound))
            car = Qnil;
        }
@@ -22434,7 +22496,7 @@ init_glyph_string (struct glyph_string *s,
 {
   memset (s, 0, sizeof *s);
   s->w = w;
-  s->f = XFRAME (WGET (w, frame));
+  s->f = XFRAME (w->frame);
 #ifdef HAVE_NTGUI
   s->hdc = hdc;
 #endif
@@ -22454,7 +22516,7 @@ init_glyph_string (struct glyph_string *s,
 /* Append the list of glyph strings with head H and tail T to the list
    with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the result.  */
 
-static inline void
+static void
 append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
                           struct glyph_string *h, struct glyph_string *t)
 {
@@ -22474,7 +22536,7 @@ append_glyph_string_lists (struct glyph_string **head, struct glyph_string **tai
    list with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the
    result.  */
 
-static inline void
+static void
 prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **tail,
                            struct glyph_string *h, struct glyph_string *t)
 {
@@ -22493,7 +22555,7 @@ prepend_glyph_string_lists (struct glyph_string **head, struct glyph_string **ta
 /* Append glyph string S to the list with head *HEAD and tail *TAIL.
    Set *HEAD and *TAIL to the resulting list.  */
 
-static inline void
+static void
 append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
                     struct glyph_string *s)
 {
@@ -22508,7 +22570,7 @@ append_glyph_string (struct glyph_string **head, struct glyph_string **tail,
    Value is a pointer to a realized face that is ready for display if
    DISPLAY_P is non-zero.  */
 
-static inline struct face *
+static struct face *
 get_char_face_and_encoding (struct frame *f, int c, int face_id,
                            XChar2b *char2b, int display_p)
 {
@@ -22541,7 +22603,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id,
    The encoding of GLYPH->u.ch is returned in *CHAR2B.  Value is
    a pointer to a realized face that is ready for display.  */
 
-static inline struct face *
+static struct face *
 get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
                             XChar2b *char2b, int *two_byte_p)
 {
@@ -22578,7 +22640,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
 /* Get glyph code of character C in FONT in the two-byte form CHAR2B.
    Return 1 if FONT has a glyph for C, otherwise return 0.  */
 
-static inline int
+static int
 get_char_glyph_code (int c, struct font *font, XChar2b *char2b)
 {
   unsigned code;
@@ -22766,7 +22828,7 @@ fill_glyph_string (struct glyph_string *s, int face_id,
   int voffset;
   int glyph_not_available_p;
 
-  eassert (s->f == XFRAME (WGET (s->w, frame)));
+  eassert (s->f == XFRAME (s->w->frame));
   eassert (s->nchars == 0);
   eassert (start >= 0 && end > start);
 
@@ -23006,7 +23068,8 @@ right_overwritten (struct glyph_string *s)
     {
       int x = 0, i;
       struct glyph *glyphs = s->row->glyphs[s->area];
-      int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+      int first = (s->first_glyph - glyphs
+                  + (s->first_glyph->type == COMPOSITE_GLYPH ? 1 : s->nchars));
       int end = s->row->used[s->area];
 
       for (i = first; i < end && s->right_overhang > x; ++i)
@@ -23029,7 +23092,8 @@ right_overwriting (struct glyph_string *s)
   int i, k, x;
   int end = s->row->used[s->area];
   struct glyph *glyphs = s->row->glyphs[s->area];
-  int first = (s->first_glyph - glyphs) + (s->cmp ? 1 : s->nchars);
+  int first = (s->first_glyph - glyphs
+              + (s->first_glyph->type == COMPOSITE_GLYPH ? 1 : s->nchars));
 
   k = -1;
   x = 0;
@@ -23050,7 +23114,7 @@ right_overwriting (struct glyph_string *s)
    first glyph following S.  LAST_X is the right-most x-position + 1
    in the drawing area.  */
 
-static inline void
+static void
 set_glyph_string_background_width (struct glyph_string *s, int start, int last_x)
 {
   /* If the face of this glyph string has to be drawn to the end of
@@ -23326,7 +23390,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
              break;                                                    \
                                                                        \
            default:                                                    \
-             abort ();                                                 \
+             emacs_abort ();                                                   \
            }                                                           \
                                                                        \
          if (s)                                                        \
@@ -23376,8 +23440,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
 
   /* Let's rather be paranoid than getting a SEGV.  */
   end = min (end, row->used[area]);
-  start = max (0, start);
-  start = min (end, start);
+  start = clip_to_bounds (0, start, end);
 
   /* Translate X to frame coordinates.  Set last_x to the right
      end of the drawing area.  */
@@ -23419,7 +23482,9 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
 
       /* If mouse highlighting is on, we may need to draw adjacent
         glyphs using mouse-face highlighting.  */
-      if (area == TEXT_AREA && row->mouse_face_p)
+      if (area == TEXT_AREA && row->mouse_face_p
+         && hlinfo->mouse_face_beg_row >= 0
+         && hlinfo->mouse_face_end_row >= 0)
        {
          struct glyph_row *mouse_beg_row, *mouse_end_row;
 
@@ -23611,7 +23676,7 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
 /* Store one glyph for IT->char_to_display in IT->glyph_row.
    Called from x_produce_glyphs when IT->glyph_row is non-null.  */
 
-static inline void
+static void
 append_glyph (struct it *it)
 {
   struct glyph *glyph;
@@ -23654,8 +23719,18 @@ append_glyph (struct it *it)
       glyph->type = CHAR_GLYPH;
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
-      glyph->left_box_line_p = it->start_of_box_run_p;
-      glyph->right_box_line_p = it->end_of_box_run_p;
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+       {
+         /* In R2L rows, the left and the right box edges need to be
+            drawn in reverse direction.  */
+         glyph->right_box_line_p = it->start_of_box_run_p;
+         glyph->left_box_line_p = it->end_of_box_run_p;
+       }
+      else
+       {
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+       }
       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
                                      || it->phys_descent > it->descent);
       glyph->glyph_not_available_p = it->glyph_not_available_p;
@@ -23667,7 +23742,7 @@ append_glyph (struct it *it)
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
          if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           abort ();
+           emacs_abort ();
          glyph->bidi_type = it->bidi_it.type;
        }
       else
@@ -23685,7 +23760,7 @@ append_glyph (struct it *it)
    IT->glyph_row.  Called from x_produce_glyphs when IT->glyph_row is
    non-null.  */
 
-static inline void
+static void
 append_composite_glyph (struct it *it)
 {
   struct glyph *glyph;
@@ -23729,8 +23804,18 @@ append_composite_glyph (struct it *it)
        }
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
-      glyph->left_box_line_p = it->start_of_box_run_p;
-      glyph->right_box_line_p = it->end_of_box_run_p;
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+       {
+         /* In R2L rows, the left and the right box edges need to be
+            drawn in reverse direction.  */
+         glyph->right_box_line_p = it->start_of_box_run_p;
+         glyph->left_box_line_p = it->end_of_box_run_p;
+       }
+      else
+       {
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+       }
       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
                                      || it->phys_descent > it->descent);
       glyph->padding_p = 0;
@@ -23741,7 +23826,7 @@ append_composite_glyph (struct it *it)
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
          if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           abort ();
+           emacs_abort ();
          glyph->bidi_type = it->bidi_it.type;
        }
       ++it->glyph_row->used[area];
@@ -23754,7 +23839,7 @@ append_composite_glyph (struct it *it)
 /* Change IT->ascent and IT->height according to the setting of
    IT->voffset.  */
 
-static inline void
+static void
 take_vertical_position_into_account (struct it *it)
 {
   if (it->voffset)
@@ -23907,8 +23992,18 @@ produce_image_glyph (struct it *it)
          glyph->type = IMAGE_GLYPH;
          glyph->avoid_cursor_p = it->avoid_cursor_p;
          glyph->multibyte_p = it->multibyte_p;
-         glyph->left_box_line_p = it->start_of_box_run_p;
-         glyph->right_box_line_p = it->end_of_box_run_p;
+         if (it->glyph_row->reversed_p && area == TEXT_AREA)
+           {
+             /* In R2L rows, the left and the right box edges need to be
+                drawn in reverse direction.  */
+             glyph->right_box_line_p = it->start_of_box_run_p;
+             glyph->left_box_line_p = it->end_of_box_run_p;
+           }
+         else
+           {
+             glyph->left_box_line_p = it->start_of_box_run_p;
+             glyph->right_box_line_p = it->end_of_box_run_p;
+           }
          glyph->overlaps_vertically_p = 0;
           glyph->padding_p = 0;
          glyph->glyph_not_available_p = 0;
@@ -23920,7 +24015,7 @@ produce_image_glyph (struct it *it)
            {
              glyph->resolved_level = it->bidi_it.resolved_level;
              if ((it->bidi_it.type & 7) != it->bidi_it.type)
-               abort ();
+               emacs_abort ();
              glyph->bidi_type = it->bidi_it.type;
            }
          ++it->glyph_row->used[area];
@@ -23967,8 +24062,18 @@ append_stretch_glyph (struct it *it, Lisp_Object object,
       glyph->type = STRETCH_GLYPH;
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
-      glyph->left_box_line_p = it->start_of_box_run_p;
-      glyph->right_box_line_p = it->end_of_box_run_p;
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+       {
+         /* In R2L rows, the left and the right box edges need to be
+            drawn in reverse direction.  */
+         glyph->right_box_line_p = it->start_of_box_run_p;
+         glyph->left_box_line_p = it->end_of_box_run_p;
+       }
+      else
+       {
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+       }
       glyph->overlaps_vertically_p = 0;
       glyph->padding_p = 0;
       glyph->glyph_not_available_p = 0;
@@ -23981,7 +24086,7 @@ append_stretch_glyph (struct it *it, Lisp_Object object,
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
          if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           abort ();
+           emacs_abort ();
          glyph->bidi_type = it->bidi_it.type;
        }
       else
@@ -24035,17 +24140,16 @@ produce_stretch_glyph (struct it *it)
   Lisp_Object prop, plist;
   int width = 0, height = 0, align_to = -1;
   int zero_width_ok_p = 0;
-  int ascent = 0;
   double tem;
-  struct face *face = NULL;
   struct font *font = NULL;
 
 #ifdef HAVE_WINDOW_SYSTEM
+  int ascent = 0;
   int zero_height_ok_p = 0;
 
   if (FRAME_WINDOW_P (it->f))
     {
-      face = FACE_FROM_ID (it->f, it->face_id);
+      struct face *face = FACE_FROM_ID (it->f, it->face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
       PREPARE_FACE_FOR_DISPLAY (it->f, face);
     }
@@ -24161,7 +24265,7 @@ produce_stretch_glyph (struct it *it)
       int n = width;
 
       if (!STRINGP (object))
-       object = WGET (it->w, buffer);
+       object = it->w->buffer;
 #ifdef HAVE_WINDOW_SYSTEM
       if (FRAME_WINDOW_P (it->f))
        append_stretch_glyph (it, object, width, height, ascent);
@@ -24236,7 +24340,7 @@ produce_special_glyphs (struct it *it, enum display_element_type what)
        }
     }
   else
-    abort ();
+    emacs_abort ();
 
 #ifdef HAVE_WINDOW_SYSTEM
   /* On a GUI frame, when the right fringe (left fringe for R2L rows)
@@ -24421,8 +24525,18 @@ append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len,
       glyph->slice.glyphless.lower_yoff = lower_yoff;
       glyph->avoid_cursor_p = it->avoid_cursor_p;
       glyph->multibyte_p = it->multibyte_p;
-      glyph->left_box_line_p = it->start_of_box_run_p;
-      glyph->right_box_line_p = it->end_of_box_run_p;
+      if (it->glyph_row->reversed_p && area == TEXT_AREA)
+       {
+         /* In R2L rows, the left and the right box edges need to be
+            drawn in reverse direction.  */
+         glyph->right_box_line_p = it->start_of_box_run_p;
+         glyph->left_box_line_p = it->end_of_box_run_p;
+       }
+      else
+       {
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+       }
       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
                                      || it->phys_descent > it->descent);
       glyph->padding_p = 0;
@@ -24433,7 +24547,7 @@ append_glyphless_glyph (struct it *it, int face_id, int for_no_font, int len,
        {
          glyph->resolved_level = it->bidi_it.resolved_level;
          if ((it->bidi_it.type & 7) != it->bidi_it.type)
-           abort ();
+           emacs_abort ();
          glyph->bidi_type = it->bidi_it.type;
        }
       ++it->glyph_row->used[area];
@@ -25292,7 +25406,7 @@ x_write_glyphs (struct glyph *start, int len)
   if (updated_row->reversed_p && chpos >= updated_row->used[TEXT_AREA])
     chpos = updated_row->used[TEXT_AREA] - 1;
 
-  BLOCK_INPUT;
+  block_input ();
 
   /* Write glyphs.  */
 
@@ -25310,7 +25424,7 @@ x_write_glyphs (struct glyph *start, int len)
       && chpos < hpos + len)
     updated_window->phys_cursor_on_p = 0;
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 
   /* Advance the output cursor.  */
   output_cursor.hpos += len;
@@ -25333,7 +25447,7 @@ x_insert_glyphs (struct glyph *start, int len)
   ptrdiff_t hpos;
 
   eassert (updated_window && updated_row);
-  BLOCK_INPUT;
+  block_input ();
   w = updated_window;
   f = XFRAME (WINDOW_FRAME (w));
 
@@ -25367,7 +25481,7 @@ x_insert_glyphs (struct glyph *start, int len)
   /* Advance the output cursor.  */
   output_cursor.hpos += len;
   output_cursor.x += shift_by_width;
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 
@@ -25388,7 +25502,7 @@ x_clear_end_of_line (int to_x)
   int from_x, from_y, to_y;
 
   eassert (updated_window && updated_row);
-  f = XFRAME (WGET (w, frame));
+  f = XFRAME (w->frame);
 
   if (updated_row->full_width_p)
     max_x = WINDOW_TOTAL_WIDTH (w);
@@ -25436,10 +25550,10 @@ x_clear_end_of_line (int to_x)
   /* Prevent inadvertently clearing to end of the X window.  */
   if (to_x > from_x && to_y > from_y)
     {
-      BLOCK_INPUT;
+      block_input ();
       FRAME_RIF (f)->clear_frame_area (f, from_x, from_y,
                                        to_x - from_x, to_y - from_y);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -25546,8 +25660,8 @@ static enum text_cursor_kinds
 get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
                        int *active_cursor)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
-  struct buffer *b = XBUFFER (WGET (w, buffer));
+  struct frame *f = XFRAME (w->frame);
+  struct buffer *b = XBUFFER (w->buffer);
   int cursor_type = DEFAULT_CURSOR;
   Lisp_Object alt_cursor;
   int non_selected = 0;
@@ -25575,7 +25689,7 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
     }
 
   /* Detect a nonselected window or nonselected frame.  */
-  else if (w != XWINDOW (FGET (f, selected_window))
+  else if (w != XWINDOW (f->selected_window)
           || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
     {
       *active_cursor = 0;
@@ -25766,7 +25880,7 @@ x_fix_overlapping_area (struct window *w, struct glyph_row *row,
 {
   int i, x;
 
-  BLOCK_INPUT;
+  block_input ();
 
   x = 0;
   for (i = 0; i < row->used[area];)
@@ -25794,7 +25908,7 @@ x_fix_overlapping_area (struct window *w, struct glyph_row *row,
        }
     }
 
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 
@@ -25858,7 +25972,7 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
 void
 erase_phys_cursor (struct window *w)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
   int hpos = w->phys_cursor.hpos;
   int vpos = w->phys_cursor.vpos;
@@ -25977,7 +26091,7 @@ void
 display_and_set_cursor (struct window *w, int on,
                        int hpos, int vpos, int x, int y)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int new_cursor_type;
   int new_cursor_width;
   int active_cursor;
@@ -26012,7 +26126,7 @@ display_and_set_cursor (struct window *w, int on,
       || (0 <= hpos && hpos < glyph_row->used[TEXT_AREA]))
     glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
 
-  eassert (interrupt_input_blocked);
+  eassert (input_blocked_p ());
 
   /* Set new_cursor_type to the cursor we want to be displayed.  */
   new_cursor_type = get_window_cursor_type (w, glyph,
@@ -26082,10 +26196,10 @@ update_window_cursor (struct window *w, int on)
       if (row->reversed_p && hpos >= row->used[TEXT_AREA])
        hpos = row->used[TEXT_AREA] - 1;
 
-      BLOCK_INPUT;
+      block_input ();
       display_and_set_cursor (w, on, hpos, vpos,
                              w->phys_cursor.x, w->phys_cursor.y);
-      UNBLOCK_INPUT;
+      unblock_input ();
     }
 }
 
@@ -26098,14 +26212,14 @@ update_cursor_in_window_tree (struct window *w, int on_p)
 {
   while (w)
     {
-      if (!NILP (WGET (w, hchild)))
-       update_cursor_in_window_tree (XWINDOW (WGET (w, hchild)), on_p);
-      else if (!NILP (WGET (w, vchild)))
-       update_cursor_in_window_tree (XWINDOW (WGET (w, vchild)), on_p);
+      if (!NILP (w->hchild))
+       update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
+      else if (!NILP (w->vchild))
+       update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
       else
        update_window_cursor (w, on_p);
 
-      w = NILP (WGET (w, next)) ? 0 : XWINDOW (WGET (w, next));
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
     }
 }
 
@@ -26117,7 +26231,7 @@ update_cursor_in_window_tree (struct window *w, int on_p)
 void
 x_update_cursor (struct frame *f, int on_p)
 {
-  update_cursor_in_window_tree (XWINDOW (FGET (f, root_window)), on_p);
+  update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
 }
 
 
@@ -26129,7 +26243,7 @@ x_update_cursor (struct frame *f, int on_p)
 void
 x_clear_cursor (struct window *w)
 {
-  if (FRAME_VISIBLE_P (XFRAME (WGET (w, frame))) && w->phys_cursor_on_p)
+  if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
     update_window_cursor (w, 0);
 }
 
@@ -26143,7 +26257,7 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row,
                          enum draw_glyphs_face draw)
 {
 #ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (XFRAME (WGET (w, frame))))
+  if (FRAME_WINDOW_P (XFRAME (w->frame)))
     {
       draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0);
       return;
@@ -26263,10 +26377,10 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
          if (row->reversed_p && hpos >= row->used[TEXT_AREA])
            hpos = row->used[TEXT_AREA] - 1;
 
-         BLOCK_INPUT;
+         block_input ();
          display_and_set_cursor (w, 1, hpos, w->phys_cursor.vpos,
                                  w->phys_cursor.x, w->phys_cursor.y);
-         UNBLOCK_INPUT;
+         unblock_input ();
        }
 #endif /* HAVE_WINDOW_SYSTEM */
     }
@@ -26276,7 +26390,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
   if (FRAME_WINDOW_P (f))
     {
       if (draw == DRAW_NORMAL_TEXT
-         && !EQ (hlinfo->mouse_face_window, FGET (f, tool_bar_window)))
+         && !EQ (hlinfo->mouse_face_window, f->tool_bar_window))
        FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->text_cursor);
       else if (draw == DRAW_MOUSE_FACE)
        FRAME_RIF (f)->define_frame_cursor (f, FRAME_X_OUTPUT (f)->hand_cursor);
@@ -26314,7 +26428,7 @@ clear_mouse_face (Mouse_HLInfo *hlinfo)
 static int
 coords_in_mouse_face_p (struct window *w, int hpos, int vpos)
 {
-  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (WGET (w, frame)));
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
 
   /* Quickly resolve the easy cases.  */
   if (!(WINDOWP (hlinfo->mouse_face_window)
@@ -26566,7 +26680,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
   /* Find the rows corresponding to START_CHARPOS and END_CHARPOS.  */
   rows_from_pos_range (w, start_charpos, end_charpos, disp_string, &r1, &r2);
   if (r1 == NULL)
-    r1 = MATRIX_ROW (w->current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+    r1 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
   /* If the before-string or display-string contains newlines,
      rows_from_pos_range skips to its last row.  Move back.  */
   if (!NILP (before_string) || !NILP (disp_string))
@@ -26588,7 +26702,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
     }
   if (r2 == NULL)
     {
-      r2 = MATRIX_ROW (w->current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+      r2 = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
       hlinfo->mouse_face_past_end = 1;
     }
   else if (!NILP (after_string))
@@ -26596,7 +26710,7 @@ mouse_face_from_buffer_pos (Lisp_Object window,
       /* If the after-string has newlines, advance to its last row.  */
       struct glyph_row *next;
       struct glyph_row *last
-       = MATRIX_ROW (w->current_matrix, XFASTINT (WGET (w, window_end_vpos)));
+       = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
 
       for (next = r2 + 1;
           next <= last
@@ -27261,7 +27375,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
                                    enum window_part area)
 {
   struct window *w = XWINDOW (window);
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 #ifdef HAVE_WINDOW_SYSTEM
   Display_Info *dpyinfo;
@@ -27345,7 +27459,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
                {
                  help_echo_string = help;
                  XSETWINDOW (help_echo_window, w);
-                 help_echo_object = WGET (w, buffer);
+                 help_echo_object = w->buffer;
                  help_echo_pos = charpos;
                }
            }
@@ -27381,7 +27495,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
            {
              Lisp_Object default_help
                = buffer_local_value_1 (Qmode_line_default_help_echo,
-                                       WGET (w, buffer));
+                                       w->buffer);
 
              if (STRINGP (default_help))
                {
@@ -27599,12 +27713,6 @@ note_mouse_highlight (struct frame *f, int x, int y)
   if (hlinfo->mouse_face_defer)
     return;
 
-  if (gc_in_progress)
-    {
-      hlinfo->mouse_face_deferred_gc = 1;
-      return;
-    }
-
   /* Which window is that in?  */
   window = window_from_coordinates (f, x, y, &part, 1);
 
@@ -27632,7 +27740,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
 #ifdef HAVE_WINDOW_SYSTEM
   /* Handle tool-bar window differently since it doesn't display a
      buffer.  */
-  if (EQ (window, FGET (f, tool_bar_window)))
+  if (EQ (window, f->tool_bar_window))
     {
       note_tool_bar_highlight (f, x, y);
       return;
@@ -27662,9 +27770,9 @@ note_mouse_highlight (struct frame *f, int x, int y)
 
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
-  b = XBUFFER (WGET (w, buffer));
+  b = XBUFFER (w->buffer);
   if (part == ON_TEXT
-      && EQ (WGET (w, window_end_valid), WGET (w, buffer))
+      && EQ (w->window_end_valid, w->buffer)
       && w->last_modified == BUF_MODIFF (b)
       && w->last_overlay_modified == BUF_OVERLAY_MODIFF (b))
     {
@@ -27871,8 +27979,8 @@ note_mouse_highlight (struct frame *f, int x, int y)
                  if (pos > 0)
                    {
                      mouse_face = get_char_property_and_overlay
-                       (make_number (pos), Qmouse_face, WGET (w, buffer), &overlay);
-                     buffer = WGET (w, buffer);
+                       (make_number (pos), Qmouse_face, w->buffer, &overlay);
+                     buffer = w->buffer;
                      disp_string = object;
                    }
                }
@@ -27898,12 +28006,12 @@ note_mouse_highlight (struct frame *f, int x, int y)
                     is the smallest.  */
                  Lisp_Object lim1 =
                    NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
-                   ? Fmarker_position (WGET (w, start))
+                   ? Fmarker_position (w->start)
                    : Qnil;
                  Lisp_Object lim2 =
                    NILP (BVAR (XBUFFER (buffer), bidi_display_reordering))
                    ? make_number (BUF_Z (XBUFFER (buffer))
-                                  - XFASTINT (WGET (w, window_end_pos)))
+                                  - XFASTINT (w->window_end_pos))
                    : Qnil;
 
                  if (NILP (overlay))
@@ -27985,11 +28093,11 @@ note_mouse_highlight (struct frame *f, int x, int y)
                    if (p > 0)
                      {
                        help = Fget_char_property (make_number (p),
-                                                  Qhelp_echo, WGET (w, buffer));
+                                                  Qhelp_echo, w->buffer);
                        if (!NILP (help))
                          {
                            charpos = p;
-                           obj = WGET (w, buffer);
+                           obj = w->buffer;
                          }
                      }
                  }
@@ -28040,7 +28148,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
                      ptrdiff_t p = string_buffer_position (obj, start);
                      if (p > 0)
                        pointer = Fget_char_property (make_number (p),
-                                                     Qpointer, WGET (w, buffer));
+                                                     Qpointer, w->buffer);
                    }
                }
              else if (BUFFERP (obj)
@@ -28078,14 +28186,14 @@ note_mouse_highlight (struct frame *f, int x, int y)
 void
 x_clear_window_mouse_face (struct window *w)
 {
-  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (WGET (w, frame)));
+  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
   Lisp_Object window;
 
-  BLOCK_INPUT;
+  block_input ();
   XSETWINDOW (window, w);
   if (EQ (window, hlinfo->mouse_face_window))
     clear_mouse_face (hlinfo);
-  UNBLOCK_INPUT;
+  unblock_input ();
 }
 
 
@@ -28100,7 +28208,7 @@ cancel_mouse_face (struct frame *f)
   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
   window = hlinfo->mouse_face_window;
-  if (! NILP (window) && XFRAME (WGET (XWINDOW (window), frame)) == f)
+  if (! NILP (window) && XFRAME (XWINDOW (window)->frame) == f)
     {
       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
@@ -28294,7 +28402,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 (WGET (w, frame))))
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame)))
     return;
 
   if (!WINDOW_RIGHTMOST_P (w)
@@ -28334,7 +28442,7 @@ x_draw_vertical_border (struct window *w)
 static int
 expose_window (struct window *w, XRectangle *fr)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   XRectangle wr, r;
   int mouse_face_overwritten_p = 0;
 
@@ -28475,21 +28583,21 @@ expose_window (struct window *w, XRectangle *fr)
 static int
 expose_window_tree (struct window *w, XRectangle *r)
 {
-  struct frame *f = XFRAME (WGET (w, frame));
+  struct frame *f = XFRAME (w->frame);
   int mouse_face_overwritten_p = 0;
 
   while (w && !FRAME_GARBAGED_P (f))
     {
-      if (!NILP (WGET (w, hchild)))
+      if (!NILP (w->hchild))
        mouse_face_overwritten_p
-         |= expose_window_tree (XWINDOW (WGET (w, hchild)), r);
-      else if (!NILP (WGET (w, vchild)))
+         |= expose_window_tree (XWINDOW (w->hchild), r);
+      else if (!NILP (w->vchild))
        mouse_face_overwritten_p
-         |= expose_window_tree (XWINDOW (WGET (w, vchild)), r);
+         |= expose_window_tree (XWINDOW (w->vchild), r);
       else
        mouse_face_overwritten_p |= expose_window (w, r);
 
-      w = NILP (WGET (w, next)) ? NULL : XWINDOW (WGET (w, next));
+      w = NILP (w->next) ? NULL : XWINDOW (w->next);
     }
 
   return mouse_face_overwritten_p;
@@ -28542,18 +28650,18 @@ expose_frame (struct frame *f, int x, int y, int w, int h)
     }
 
   TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
-  mouse_face_overwritten_p = expose_window_tree (XWINDOW (FGET (f, root_window)), &r);
+  mouse_face_overwritten_p = expose_window_tree (XWINDOW (f->root_window), &r);
 
-  if (WINDOWP (FGET (f, tool_bar_window)))
+  if (WINDOWP (f->tool_bar_window))
     mouse_face_overwritten_p
-      |= expose_window (XWINDOW (FGET (f, tool_bar_window)), &r);
+      |= expose_window (XWINDOW (f->tool_bar_window), &r);
 
 #ifdef HAVE_X_WINDOWS
 #ifndef MSDOS
 #ifndef USE_X_TOOLKIT
-  if (WINDOWP (FGET (f, menu_bar_window)))
+  if (WINDOWP (f->menu_bar_window))
     mouse_face_overwritten_p
-      |= expose_window (XWINDOW (FGET (f, menu_bar_window)), &r);
+      |= expose_window (XWINDOW (f->menu_bar_window), &r);
 #endif /* not USE_X_TOOLKIT */
 #endif
 #endif
@@ -28655,6 +28763,7 @@ syms_of_xdisp (void)
   staticpro (&Vmessage_stack);
 
   DEFSYM (Qinhibit_redisplay, "inhibit-redisplay");
+  DEFSYM (Qredisplay_internal, "redisplay_internal (C function)");
 
   message_dolog_marker1 = Fmake_marker ();
   staticpro (&message_dolog_marker1);
@@ -28894,12 +29003,6 @@ A value of nil means to respect the value of `truncate-lines'.
 If `word-wrap' is enabled, you might want to reduce this.  */);
   Vtruncate_partial_width_windows = make_number (50);
 
-  DEFVAR_BOOL ("mode-line-inverse-video", mode_line_inverse_video,
-    doc: /* When nil, display the mode-line/header-line/menu-bar in the default face.
-Any other value means to use the appropriate face, `mode-line',
-`header-line', or `menu' respectively.  */);
-  mode_line_inverse_video = 1;
-
   DEFVAR_LISP ("line-number-display-limit", Vline_number_display_limit,
     doc: /* Maximum buffer size for which line number should be displayed.
 If the buffer is bigger than this, the line number does not appear
@@ -28952,7 +29055,7 @@ and is used only on frames for which no explicit name has been set
     doc: /* Maximum number of lines to keep in the message log buffer.
 If nil, disable message logging.  If t, log messages but don't truncate
 the buffer when it becomes large.  */);
-  Vmessage_log_max = make_number (100);
+  Vmessage_log_max = make_number (1000);
 
   DEFVAR_LISP ("window-size-change-functions", Vwindow_size_change_functions,
     doc: /* Functions called before redisplay, if window sizes have changed.
@@ -29266,6 +29369,10 @@ Its value should be an ASCII acronym string, `hex-code', `empty-box', or
   Vglyphless_char_display = Fmake_char_table (Qglyphless_char_display, Qnil);
   Fset_char_table_extra_slot (Vglyphless_char_display, make_number (0),
                              Qempty_box);
+
+  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;
 }
 
 
@@ -29281,7 +29388,7 @@ init_xdisp (void)
   if (!noninteractive)
     {
       struct window *m = XWINDOW (minibuf_window);
-      Lisp_Object frame = WGET (m, frame);
+      Lisp_Object frame = m->frame;
       struct frame *f = XFRAME (frame);
       Lisp_Object root = FRAME_ROOT_WINDOW (f);
       struct window *r = XWINDOW (root);
@@ -29289,12 +29396,13 @@ init_xdisp (void)
 
       echo_area_window = minibuf_window;
 
-      WSET (r, top_line, make_number (FRAME_TOP_MARGIN (f)));
-      WSET (r, total_lines, make_number (FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f)));
-      WSET (r, total_cols, make_number (FRAME_COLS (f)));
-      WSET (m, top_line, make_number (FRAME_LINES (f) - 1));
-      WSET (m, total_lines, make_number (1));
-      WSET (m, total_cols, make_number (FRAME_COLS (f)));
+      wset_top_line (r, make_number (FRAME_TOP_MARGIN (f)));
+      wset_total_lines
+       (r, make_number (FRAME_LINES (f) - 1 - FRAME_TOP_MARGIN (f)));
+      wset_total_cols (r, make_number (FRAME_COLS (f)));
+      wset_top_line (m, make_number (FRAME_LINES (f) - 1));
+      wset_total_lines (m, make_number (1));
+      wset_total_cols (m, make_number (FRAME_COLS (f)));
 
       scratch_glyph_row.glyphs[TEXT_AREA] = scratch_glyphs;
       scratch_glyph_row.glyphs[TEXT_AREA + 1]
@@ -29318,11 +29426,7 @@ init_xdisp (void)
   help_echo_showing_p = 0;
 }
 
-/* Since w32 does not support atimers, it defines its own implementation of
-   the following three functions in w32fns.c.  */
-#ifndef WINDOWSNT
-
-/* Platform-independent portion of hourglass implementation. */
+/* Platform-independent portion of hourglass implementation.  */
 
 /* Cancel a currently active hourglass timer, and start a new one.  */
 void
@@ -29344,6 +29448,13 @@ start_hourglass (void)
   else
     delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0);
 
+#ifdef HAVE_NTGUI
+  {
+    extern void w32_note_current_window (void);
+    w32_note_current_window ();
+  }
+#endif /* HAVE_NTGUI */
+
   hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
                                   show_hourglass, NULL);
 #endif
@@ -29366,4 +29477,3 @@ cancel_hourglass (void)
     hide_hourglass ();
 #endif
 }
-#endif /* ! WINDOWSNT  */