Minor integer overflow fixes.
[bpt/emacs.git] / src / window.c
index df7878f..e277041 100644 (file)
@@ -20,8 +20,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
-#define WINDOW_INLINE EXTERN_INLINE
-
 #include <stdio.h>
 
 #include "lisp.h"
@@ -39,40 +37,31 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "blockinput.h"
 #include "intervals.h"
 #include "termhooks.h"         /* For FRAME_TERMINAL.  */
-
-#ifdef HAVE_X_WINDOWS
-#include "xterm.h"
-#endif /* HAVE_X_WINDOWS */
-#ifdef HAVE_NTGUI
-#include "w32term.h"
-#endif
+#ifdef HAVE_WINDOW_SYSTEM
+#include TERM_HEADER
+#endif /* HAVE_WINDOW_SYSTEM */
 #ifdef MSDOS
 #include "msdos.h"
 #endif
-#ifdef HAVE_NS
-#include "nsterm.h"
-#endif
 
 Lisp_Object Qwindowp, Qwindow_live_p;
 static Lisp_Object Qwindow_valid_p;
-static Lisp_Object Qwindow_configuration_p, Qrecord_window_buffer;
+static Lisp_Object Qwindow_configuration_p;
+static Lisp_Object Qrecord_window_buffer;
 static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer;
 static Lisp_Object Qreplace_buffer_in_windows, Qget_mru_window;
 static Lisp_Object Qwindow_resize_root_window, Qwindow_resize_root_window_vertically;
+static Lisp_Object Qwindow_pixel_to_total;
 static Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command;
 static Lisp_Object Qsafe, Qabove, Qbelow, Qwindow_size, Qclone_of;
 
 static int displayed_window_lines (struct window *);
 static int count_windows (struct window *);
 static int get_leaf_windows (struct window *, struct window **, int);
-static void window_scroll (Lisp_Object, EMACS_INT, int, int);
-static void window_scroll_pixel_based (Lisp_Object, int, int, int);
-static void window_scroll_line_based (Lisp_Object, int, int, int);
-static int freeze_window_start (struct window *, void *);
-static Lisp_Object window_list (void);
+static void window_scroll (Lisp_Object, EMACS_INT, bool, int);
+static void window_scroll_pixel_based (Lisp_Object, int, bool, int);
+static void window_scroll_line_based (Lisp_Object, int, bool, int);
 static int add_window_to_list (struct window *, void *);
-static int candidate_window_p (Lisp_Object, Lisp_Object, Lisp_Object,
-                               Lisp_Object);
 static Lisp_Object next_window (Lisp_Object, Lisp_Object,
                                 Lisp_Object, int);
 static void decode_next_window_args (Lisp_Object *, Lisp_Object *,
@@ -86,9 +75,18 @@ static int foreach_window_1 (struct window *,
 static Lisp_Object window_list_1 (Lisp_Object, Lisp_Object, Lisp_Object);
 static int window_resize_check (struct window *, bool);
 static void window_resize_apply (struct window *, bool);
+static void window_resize_apply_total (struct window *, bool);
 static Lisp_Object select_window (Lisp_Object, Lisp_Object, int);
 static void select_window_1 (Lisp_Object, bool);
 
+static struct window *set_window_fringes (struct window *, Lisp_Object,
+                                         Lisp_Object, Lisp_Object);
+static struct window *set_window_margins (struct window *, Lisp_Object,
+                                         Lisp_Object);
+static struct window *set_window_scroll_bars (struct window *, Lisp_Object,
+                                             Lisp_Object, Lisp_Object);
+static void apply_window_adjustment (struct window *);
+
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
    always be a leaf window, and its buffer is selected by
@@ -116,6 +114,9 @@ Lisp_Object minibuf_selected_window;
 /* Hook run at end of temp_output_buffer_show.  */
 static Lisp_Object Qtemp_buffer_show_hook;
 
+/* Incremented for each window created.  */
+static int sequence_number;
+
 /* Nonzero after init_window_once has finished.  */
 static int window_initialized;
 
@@ -130,6 +131,12 @@ static int window_scroll_pixel_based_preserve_y;
 static EMACS_INT window_scroll_preserve_hpos;
 static EMACS_INT window_scroll_preserve_vpos;
 \f
+static void
+CHECK_WINDOW_CONFIGURATION (Lisp_Object x)
+{
+  CHECK_TYPE (WINDOW_CONFIGURATIONP (x), Qwindow_configuration_p, x);
+}
+
 /* These setters are used only in this file, so they can be private.  */
 static void
 wset_combination_limit (struct window *w, Lisp_Object val)
@@ -147,21 +154,6 @@ wset_display_table (struct window *w, Lisp_Object val)
   w->display_table = val;
 }
 static void
-wset_hchild (struct window *w, Lisp_Object val)
-{
-  w->hchild = val;
-}
-static void
-wset_left_fringe_width (struct window *w, Lisp_Object val)
-{
-  w->left_fringe_width = val;
-}
-static void
-wset_left_margin_cols (struct window *w, Lisp_Object val)
-{
-  w->left_margin_cols = val;
-}
-static void
 wset_new_normal (struct window *w, Lisp_Object val)
 {
   w->new_normal = val;
@@ -192,21 +184,6 @@ wset_pointm (struct window *w, Lisp_Object val)
   w->pointm = val;
 }
 static void
-wset_right_fringe_width (struct window *w, Lisp_Object val)
-{
-  w->right_fringe_width = val;
-}
-static void
-wset_right_margin_cols (struct window *w, Lisp_Object val)
-{
-  w->right_margin_cols = val;
-}
-static void
-wset_scroll_bar_width (struct window *w, Lisp_Object val)
-{
-  w->scroll_bar_width = val;
-}
-static void
 wset_start (struct window *w, Lisp_Object val)
 {
   w->start = val;
@@ -217,11 +194,6 @@ wset_temslot (struct window *w, Lisp_Object val)
   w->temslot = val;
 }
 static void
-wset_vchild (struct window *w, Lisp_Object val)
-{
-  w->vchild = val;
-}
-static void
 wset_vertical_scroll_bar_type (struct window *w, Lisp_Object val)
 {
   w->vertical_scroll_bar_type = val;
@@ -231,6 +203,29 @@ wset_window_parameters (struct window *w, Lisp_Object val)
 {
   w->window_parameters = val;
 }
+static void
+wset_combination (struct window *w, bool horflag, Lisp_Object val)
+{
+  /* Since leaf windows never becomes non-leaf, there should
+     be no buffer and markers in start and pointm fields of W.  */
+  eassert (!BUFFERP (w->contents) && NILP (w->start) && NILP (w->pointm));
+  w->contents = val;
+  /* When an internal window is deleted and VAL is nil, HORFLAG
+     is meaningless.  */
+  if (!NILP (val))
+    w->horizontal = horflag;
+}
+
+/* Nonzero if leaf window W doesn't reflect the actual state
+   of displayed buffer due to its text or overlays change.  */
+
+bool
+window_outdated (struct window *w)
+{
+  struct buffer *b = XBUFFER (w->contents);
+  return (w->last_modified < BUF_MODIFF (b)
+         || w->last_overlay_modified < BUF_OVERLAY_MODIFF (b));
+}
 
 struct window *
 decode_live_window (register Lisp_Object window)
@@ -275,9 +270,9 @@ static void
 adjust_window_count (struct window *w, int arg)
 {
   eassert (eabs (arg) == 1);
-  if (BUFFERP (w->buffer))
+  if (BUFFERP (w->contents))
     {
-      struct buffer *b = XBUFFER (w->buffer);
+      struct buffer *b = XBUFFER (w->contents);
 
       if (b->base_buffer)
        b = b->base_buffer;
@@ -296,7 +291,11 @@ void
 wset_buffer (struct window *w, Lisp_Object val)
 {
   adjust_window_count (w, -1);
-  w->buffer = val;
+  if (BUFFERP (val))
+    /* Make sure that we do not assign the buffer
+       to an internal window.  */
+    eassert (MARKERP (w->start) && MARKERP (w->pointm));
+  w->contents = val;
   adjust_window_count (w, 1);
 }
 
@@ -394,15 +393,8 @@ the first window of that frame.  */)
       window = XFRAME (frame_or_window)->root_window;
     }
 
-  while (NILP (XWINDOW (window)->buffer))
-    {
-      if (! NILP (XWINDOW (window)->hchild))
-       window = XWINDOW (window)->hchild;
-      else if (! NILP (XWINDOW (window)->vchild))
-       window = XWINDOW (window)->vchild;
-      else
-       emacs_abort ();
-    }
+  while (WINDOWP (XWINDOW (window)->contents))
+    window = XWINDOW (window)->contents;
 
   return window;
 }
@@ -484,20 +476,22 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
   CHECK_LIVE_WINDOW (window);
 
   w = XWINDOW (window);
-  w->frozen_window_start_p = 0;
-
-  if (NILP (norecord))
-    {
-      w->use_time = ++window_select_count;
-      record_buffer (w->buffer);
-    }
 
   /* Make the selected window's buffer current.  */
-  Fset_buffer (w->buffer);
+  Fset_buffer (w->contents);
 
   if (EQ (window, selected_window) && !inhibit_point_swap)
-    return window;
+    /* `switch-to-buffer' uses (select-window (selected-window)) as a "clever"
+       way to call record_buffer from Elisp, so it's important that we call
+       record_buffer before returning here.  */
+    goto record_and_return;
 
+  if (NILP (norecord))
+    /* Mark the window for redisplay since the selected-window has a different
+       mode-line.  */
+    wset_redisplay (XWINDOW (selected_window));
+  else
+    redisplay_other_windows ();
   sf = SELECTED_FRAME ();
   if (XFRAME (WINDOW_FRAME (w)) != sf)
     {
@@ -515,9 +509,20 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
     fset_selected_window (sf, window);
 
   select_window_1 (window, inhibit_point_swap);
+  bset_last_selected_window (XBUFFER (w->contents), window);
+  if (NILP (norecord))
+    wset_redisplay (w);
+
+ record_and_return:
+  /* record_buffer can run QUIT, so make sure it is run only after we have
+     re-established the invariant between selected_window and selected_frame,
+     otherwise the temporary broken invariant might "escape" (bug#14161).  */
+  if (NILP (norecord))
+    {
+      w->use_time = ++window_select_count;
+      record_buffer (w->contents);
+    }
 
-  bset_last_selected_window (XBUFFER (w->buffer), window);
-  windows_or_buffers_changed++;
   return window;
 }
 
@@ -533,10 +538,10 @@ select_window_1 (Lisp_Object window, bool inhibit_point_swap)
   if (!inhibit_point_swap)
     {
       struct window *ow = XWINDOW (selected_window);
-      if (! NILP (ow->buffer))
-       set_marker_both (ow->pointm, ow->buffer,
-                        BUF_PT (XBUFFER (ow->buffer)),
-                        BUF_PT_BYTE (XBUFFER (ow->buffer)));
+      if (BUFFERP (ow->contents))
+       set_marker_both (ow->pointm, ow->contents,
+                        BUF_PT (XBUFFER (ow->contents)),
+                        BUF_PT_BYTE (XBUFFER (ow->contents)));
     }
 
   selected_window = window;
@@ -546,15 +551,7 @@ select_window_1 (Lisp_Object window, bool inhibit_point_swap)
      than one window.  It also matters when
      redisplay_window has altered point after scrolling,
      because it makes the change only in the window.  */
-  {
-    register ptrdiff_t new_point = marker_position (XWINDOW (window)->pointm);
-    if (new_point < BEGV)
-      SET_PT (BEGV);
-    else if (new_point > ZV)
-      SET_PT (ZV);
-    else
-      SET_PT (new_point);
-  }
+  set_point_from_marker (XWINDOW (window)->pointm);
 }
 
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
@@ -581,7 +578,8 @@ If WINDOW is omitted or nil, it defaults to the selected window.
 Return nil for an internal window or a deleted window.  */)
   (Lisp_Object window)
 {
-  return decode_any_window (window)->buffer;
+  struct window *w = decode_any_window (window);
+  return WINDOW_LEAF_P (w) ? w->contents : Qnil;
 }
 
 DEFUN ("window-parent", Fwindow_parent, Swindow_parent, 0, 1, 0,
@@ -601,7 +599,8 @@ Return nil if WINDOW is an internal window whose children form a
 horizontal combination.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->vchild;
+  struct window *w = decode_valid_window (window);
+  return WINDOW_VERTICAL_COMBINATION_P (w) ? w->contents : Qnil;
 }
 
 DEFUN ("window-left-child", Fwindow_left_child, Swindow_left_child, 0, 1, 0,
@@ -612,7 +611,8 @@ Return nil if WINDOW is an internal window whose children form a
 vertical combination.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->hchild;
+  struct window *w = decode_valid_window (window);
+  return WINDOW_HORIZONTAL_COMBINATION_P (w) ? w->contents : Qnil;
 }
 
 DEFUN ("window-next-sibling", Fwindow_next_sibling, Swindow_next_sibling, 0, 1, 0,
@@ -635,30 +635,37 @@ Return nil if WINDOW has no previous sibling.  */)
 
 DEFUN ("window-combination-limit", Fwindow_combination_limit, Swindow_combination_limit, 1, 1, 0,
        doc: /* Return combination limit of window WINDOW.
+WINDOW must be a valid window used in horizontal or vertical combination.
 If the return value is nil, child windows of WINDOW can be recombined with
 WINDOW's siblings.  A return value of t means that child windows of
-WINDOW are never \(re-)combined with WINDOW's siblings.
-
-WINDOW must be a valid window.  The return value is meaningful for
-internal windows only.  */)
+WINDOW are never \(re-)combined with WINDOW's siblings.  */)
   (Lisp_Object window)
 {
+  struct window *w;
+
   CHECK_VALID_WINDOW (window);
-  return XWINDOW (window)->combination_limit;
+  w = XWINDOW (window);
+  if (WINDOW_LEAF_P (w))
+    error ("Combination limit is meaningful for internal windows only");
+  return w->combination_limit;
 }
 
 DEFUN ("set-window-combination-limit", Fset_window_combination_limit, Sset_window_combination_limit, 2, 2, 0,
        doc: /* Set combination limit of window WINDOW to LIMIT; return LIMIT.
+WINDOW must be a valid window used in horizontal or vertical combination.
 If LIMIT is nil, child windows of WINDOW can be recombined with WINDOW's
 siblings.  LIMIT t means that child windows of WINDOW are never
 \(re-)combined with WINDOW's siblings.  Other values are reserved for
-future use.
-
-WINDOW must be a valid window.  Setting the combination limit is
-meaningful for internal windows only.  */)
+future use.  */)
   (Lisp_Object window, Lisp_Object limit)
 {
-  wset_combination_limit (decode_valid_window (window), limit);
+  struct window *w;
+
+  CHECK_VALID_WINDOW (window);
+  w = XWINDOW (window);
+  if (WINDOW_LEAF_P (w))
+    error ("Combination limit is meaningful for internal windows only");
+  wset_combination_limit (w, limit);
   return limit;
 }
 
@@ -673,6 +680,31 @@ selected one.  */)
   return make_number (decode_live_window (window)->use_time);
 }
 \f
+DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
+       doc: /* Return the pixel width of window WINDOW.
+WINDOW must be a valid window and defaults to the selected one.
+
+The return value includes the fringes and margins of WINDOW as well as
+any vertical dividers or scroll bars belonging to WINDOW.  If WINDOW is
+an internal window, its pixel width is the width of the screen areas
+spanned by its children.  */)
+     (Lisp_Object window)
+{
+  return make_number (decode_valid_window (window)->pixel_width);
+}
+
+DEFUN ("window-pixel-height", Fwindow_pixel_height, Swindow_pixel_height, 0, 1, 0,
+       doc: /* Return the pixel height of window WINDOW.
+WINDOW must be a valid window and defaults to the selected one.
+
+The return value includes the mode line and header line, if any.  If
+WINDOW is an internal window, its pixel height is the height of the
+screen areas spanned by its children.  */)
+  (Lisp_Object window)
+{
+  return make_number (decode_valid_window (window)->pixel_height);
+}
+
 DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 1, 0,
        doc: /* Return the total height, in lines, of window WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
@@ -685,7 +717,7 @@ On a graphical display, this total height is reported as an
 integer multiple of the default character height.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->total_lines;
+  return make_number (decode_valid_window (window)->total_lines);
 }
 
 DEFUN ("window-total-width", Fwindow_total_width, Swindow_total_width, 0, 1, 0,
@@ -700,7 +732,7 @@ On a graphical display, this total width is reported as an
 integer multiple of the default character width.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->total_cols;
+  return make_number (decode_valid_window (window)->total_cols);
 }
 
 DEFUN ("window-new-total", Fwindow_new_total, Swindow_new_total, 0, 1, 0,
@@ -730,6 +762,30 @@ WINDOW must be a valid window and defaults to the selected one.  */)
   return decode_valid_window (window)->new_normal;
 }
 
+DEFUN ("window-new-pixel", Fwindow_new_pixel, Swindow_new_pixel, 0, 1, 0,
+       doc: /* Return new pixel size of window WINDOW.
+WINDOW must be a valid window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return decode_valid_window (window)->new_pixel;
+}
+
+DEFUN ("window-pixel-left", Fwindow_pixel_left, Swindow_pixel_left, 0, 1, 0,
+       doc: /* Return left pixel edge of window WINDOW.
+WINDOW must be a valid window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return make_number (decode_valid_window (window)->pixel_left);
+}
+
+DEFUN ("window-pixel-top", Fwindow_pixel_top, Swindow_pixel_top, 0, 1, 0,
+       doc: /* Return top pixel edge of window WINDOW.
+WINDOW must be a valid window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return make_number (decode_valid_window (window)->pixel_top);
+}
+
 DEFUN ("window-left-column", Fwindow_left_column, Swindow_left_column, 0, 1, 0,
        doc: /* Return left column of window WINDOW.
 This is the distance, in columns, between the left edge of WINDOW and
@@ -739,7 +795,7 @@ value is 0 if there is no window to the left of WINDOW.
 WINDOW must be a valid window and defaults to the selected one.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->left_col;
+  return make_number (decode_valid_window (window)->left_col);
 }
 
 DEFUN ("window-top-line", Fwindow_top_line, Swindow_top_line, 0, 1, 0,
@@ -751,82 +807,125 @@ there is no window above WINDOW.
 WINDOW must be a valid window and defaults to the selected one.  */)
   (Lisp_Object window)
 {
-  return decode_valid_window (window)->top_line;
+  return make_number (decode_valid_window (window)->top_line);
 }
 
 /* Return the number of lines of W's body.  Don't count any mode or
    header line of W.  */
 
 static int
-window_body_lines (struct window *w)
+window_body_height (struct window *w, bool pixelwise)
 {
-  int height = XFASTINT (w->total_lines);
-
-  if (!MINI_WINDOW_P (w))
-    {
-      if (WINDOW_WANTS_MODELINE_P (w))
-       --height;
-      if (WINDOW_WANTS_HEADER_LINE_P (w))
-       --height;
-    }
+  int pixels = (w->pixel_height
+               - WINDOW_BOTTOM_DIVIDER_WIDTH (w)
+               - WINDOW_HEADER_LINE_HEIGHT (w)
+               - WINDOW_MODE_LINE_HEIGHT (w));
+  int unit = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w));
 
-  return height;
+  return pixelwise ? pixels : ((pixels + unit - 1) / unit);
 }
 
 /* Return the number of columns of W's body.  Don't count columns
    occupied by the scroll bar or the vertical bar separating W from its
    right sibling.  On window-systems don't count fringes or display
    margins either.  */
-
 int
-window_body_cols (struct window *w)
+window_body_width (struct window *w, bool pixelwise)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  int width = XINT (w->total_cols);
 
-  if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
-    /* Scroll bars occupy a few columns.  */
-    width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
-  else if (!FRAME_WINDOW_P (f)
-          && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
-    /* The column of `|' characters separating side-by-side windows
-       occupies one column only.  */
-    width -= 1;
+  int pixels = (w->pixel_width
+               - WINDOW_RIGHT_DIVIDER_WIDTH (w)
+               - (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
+                  ? WINDOW_SCROLL_BAR_AREA_WIDTH (w)
+                  : ((!FRAME_WINDOW_P (f)
+                      && !WINDOW_RIGHTMOST_P (w)
+                      && !WINDOW_RIGHT_DIVIDER_WIDTH (w)
+                      && !WINDOW_FULL_WIDTH_P (w))
+                     /* According to Eli this is either 1 or 0.  */
+                     ? 1 : 0))
+               - WINDOW_MARGINS_WIDTH (w)
+               - (FRAME_WINDOW_P (f)
+                  ? WINDOW_FRINGES_WIDTH (w)
+                  : 0));
+  int unit = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w));
+
+  return pixelwise ? pixels : ((pixels + unit - 1) / unit);
+}
+
+DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0,
+       doc: /* Return the height, in lines, of WINDOW's text area.
+WINDOW must be a live window and defaults to the selected one.
 
-  /* Display margins cannot be used for normal text.  */
-  width -= WINDOW_LEFT_MARGIN_COLS (w) + WINDOW_RIGHT_MARGIN_COLS (w);
+Optional argument PIXELWISE non-nil means return the height in pixels.
 
-  if (FRAME_WINDOW_P (f))
-    /* On window-systems, fringes cannot be used for normal text.  */
-    width -= WINDOW_FRINGE_COLS (w);
+The returned height does not include the mode line or header line.  On a
+graphical display, the height is expressed as an integer multiple of the
+default character height if PIXELWISE is nil.
 
-  return width;
+If PIXELWISE is nil and a line at the bottom of the text area is only
+partially visible, that counts as a whole line; to exclude
+partially-visible lines, use `window-text-height'.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
+{
+  return make_number (window_body_height (decode_live_window (window),
+                                         NILP (pixelwise) ? 0 : 1));
 }
 
-DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 1, 0,
-       doc: /* Return the height, in lines, of WINDOW's text area.
+DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
+       doc: /* Return the width, in columns, of WINDOW's text area.
 WINDOW must be a live window and defaults to the selected one.
 
-The returned height does not include the mode line or header line.
-On a graphical display, the height is expressed as an integer multiple
-of the default character height.  If a line at the bottom of the text
-area is only partially visible, that counts as a whole line; to
-exclude partially-visible lines, use `window-text-height'.  */)
+Optional argument PIXELWISE non-nil means return the width in pixels.
+
+The return value does not include any vertical dividers, fringe or
+marginal areas, or scroll bars.  On a graphical display, the width is
+expressed as an integer multiple of the default character width if
+PIXELWISE is nil.
+
+If PIXELWISE is nil and a column at the right of the text area is only
+partially visible, that counts as a whole column; to exclude
+partially-visible columns, use `window-text-width'.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
+{
+  return make_number (window_body_width (decode_live_window (window),
+                                        NILP (pixelwise) ? 0 : 1));
+}
+
+DEFUN ("window-mode-line-height", Fwindow_mode_line_height,
+       Swindow_mode_line_height, 0, 1, 0,
+       doc: /* Return the height in pixel of WINDOW's mode-line.
+WINDOW must be a live window and defaults to the selected one.  */)
   (Lisp_Object window)
 {
-  return make_number (window_body_lines (decode_live_window (window)));
+  return (make_number (WINDOW_MODE_LINE_HEIGHT (decode_live_window (window))));
 }
 
-DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 1, 0,
-       doc: /* Return the width, in columns, of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one.
+DEFUN ("window-header-line-height", Fwindow_header_line_height,
+       Swindow_header_line_height, 0, 1, 0,
+       doc: /* Return the height in pixel of WINDOW's header-line.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return (make_number (WINDOW_HEADER_LINE_HEIGHT (decode_live_window (window))));
+}
 
-The return value does not include any vertical dividers, fringe or
-marginal areas, or scroll bars.  On a graphical display, the width is
-expressed as an integer multiple of the default character width.  */)
+DEFUN ("window-right-divider-width", Fwindow_right_divider_width,
+       Swindow_right_divider_width, 0, 1, 0,
+       doc: /* Return the width of WINDOW's right divider.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return (make_number (WINDOW_RIGHT_DIVIDER_WIDTH (decode_live_window (window))));
+}
+
+DEFUN ("window-bottom-divider-width", Fwindow_bottom_divider_width,
+       Swindow_bottom_divider_width, 0, 1, 0,
+       doc: /* Return the width of WINDOW's bottom divider.
+WINDOW must be a live window and defaults to the selected one.  */)
   (Lisp_Object window)
 {
-  return make_number (window_body_cols (decode_live_window (window)));
+  return (make_number (WINDOW_BOTTOM_DIVIDER_WIDTH (decode_live_window (window))));
 }
 
 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
@@ -853,7 +952,7 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll)
 
   /* Prevent redisplay shortcuts when changing the hscroll.  */
   if (w->hscroll != new_hscroll)
-    XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+    XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1;
 
   w->hscroll = new_hscroll;
   return make_number (new_hscroll);
@@ -949,7 +1048,7 @@ calc_absolute_offset (struct window *w, int *add_x, int *add_y)
 #endif
 #ifdef FRAME_TOOLBAR_TOP_HEIGHT
   *add_y += FRAME_TOOLBAR_TOP_HEIGHT (f);
-#elif FRAME_TOOLBAR_HEIGHT
+#elif defined (FRAME_TOOLBAR_HEIGHT)
   *add_y += FRAME_TOOLBAR_HEIGHT (f);
 #endif
 #ifdef FRAME_NS_TITLEBAR_HEIGHT
@@ -1076,11 +1175,15 @@ display margins, fringes, header line, and/or mode line.  */)
 
 /* Test if the character at column X, row Y is within window W.
    If it is not, return ON_NOTHING;
+   if it is on the window's vertical divider, return
+      ON_RIGHT_DIVIDER;
+   if it is on the window's horizontal divider, return
+      ON_BOTTOM_DIVIDER;
    if it is in the window's text area, return ON_TEXT;
    if it is on the window's modeline, return ON_MODE_LINE;
    if it is on the border between the window and its right sibling,
-      return ON_VERTICAL_BORDER.
-   if it is on a scroll bar, return ON_SCROLL_BAR.
+      return ON_VERTICAL_BORDER;
+   if it is on a scroll bar, return ON_SCROLL_BAR;
    if it is on the window's top line, return ON_HEADER_LINE;
    if it is in left or right fringe of the window,
       return ON_LEFT_FRINGE or ON_RIGHT_FRINGE;
@@ -1108,13 +1211,28 @@ coordinates_in_window (register struct window *w, int x, int y)
   if (y < top_y || y >= bottom_y || x < left_x || x >= right_x)
     return ON_NOTHING;
 
-  /* On the mode line or header line?   */
-  if ((WINDOW_WANTS_MODELINE_P (w)
-       && y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
-       && (part = ON_MODE_LINE))
-      || (WINDOW_WANTS_HEADER_LINE_P (w)
-         && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
-         && (part = ON_HEADER_LINE)))
+  /* On vertical window divider (which prevails horizontal
+     dividers)?  */
+  if (!WINDOW_RIGHTMOST_P (w)
+      && WINDOW_RIGHT_DIVIDER_WIDTH (w)
+      && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w)
+      && x <= right_x)
+    return ON_RIGHT_DIVIDER;
+  /* On the horizontal window divider?  */
+  else if (WINDOW_BOTTOM_DIVIDER_WIDTH (w)
+          && y >= (bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+          && y <= bottom_y)
+    return ON_BOTTOM_DIVIDER;
+  /* On the mode or header line?   */
+  else if ((WINDOW_WANTS_MODELINE_P (w)
+           && y >= (bottom_y
+                    - CURRENT_MODE_LINE_HEIGHT (w)
+                    - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+           && y <= bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w)
+           && (part = ON_MODE_LINE))
+          || (WINDOW_WANTS_HEADER_LINE_P (w)
+              && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
+              && (part = ON_HEADER_LINE)))
     {
       /* If it's under/over the scroll bar portion of the mode/header
         line, say it's on the vertical line.  That's to be able to
@@ -1137,7 +1255,7 @@ coordinates_in_window (register struct window *w, int x, int y)
   if (w->pseudo_window_p)
     {
       left_x = 0;
-      right_x = WINDOW_TOTAL_WIDTH (w) - 1;
+      right_x = WINDOW_PIXEL_WIDTH (w) - 1;
     }
   else
     {
@@ -1167,6 +1285,8 @@ coordinates_in_window (register struct window *w, int x, int y)
      terminals, the vertical line's x coordinate is right_x.  */
   else if (!w->pseudo_window_p
           && !WINDOW_RIGHTMOST_P (w)
+          /* Why check ux if we are not the rightmost window?  Also
+             shouldn't a pseudo window always be rightmost?  */
           && x > right_x - ux)
     return ON_VERTICAL_BORDER;
 
@@ -1222,7 +1342,7 @@ window_relative_x_coord (struct window *w, enum window_part part, int x)
     case ON_RIGHT_MARGIN:
       return (x + 1
              - ((w->pseudo_window_p)
-                ? WINDOW_TOTAL_WIDTH (w)
+                ? WINDOW_PIXEL_WIDTH (w)
                 : WINDOW_BOX_RIGHT_EDGE_X (w))
              + window_box_width (w, RIGHT_MARGIN_AREA)
              + ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
@@ -1307,6 +1427,12 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
       /* Historically we are supposed to return nil in this case.  */
       return Qnil;
 
+    case ON_RIGHT_DIVIDER:
+      return Qright_divider;
+
+    case ON_BOTTOM_DIVIDER:
+      return Qbottom_divider;
+
     default:
       emacs_abort ();
     }
@@ -1332,7 +1458,7 @@ struct check_window_data
 static int
 check_window_containing (struct window *w, void *user_data)
 {
-  struct check_window_data *cw = (struct check_window_data *) user_data;
+  struct check_window_data *cw = user_data;
   enum window_part found;
   int continue_p = 1;
 
@@ -1381,6 +1507,7 @@ window_from_coordinates (struct frame *f, int x, int y,
   cw.window = &window, cw.x = x, cw.y = y; cw.part = part;
   foreach_window (f, check_window_containing, &cw);
 
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
   /* If not found above, see if it's in the tool bar window, if a tool
      bar exists.  */
   if (NILP (window)
@@ -1393,6 +1520,7 @@ window_from_coordinates (struct frame *f, int x, int y,
       *part = ON_TEXT;
       window = f->tool_bar_window;
     }
+#endif
 
   return window;
 }
@@ -1434,7 +1562,7 @@ correct to return the top-level value of `point', outside of any
   register struct window *w = decode_live_window (window);
 
   if (w == XWINDOW (selected_window))
-    return make_number (BUF_PT (XBUFFER (w->buffer)));
+    return make_number (BUF_PT (XBUFFER (w->contents)));
   else
     return Fmarker_position (w->pointm);
 }
@@ -1476,16 +1604,19 @@ if it isn't already recorded.  */)
   Lisp_Object buf;
   struct buffer *b;
 
-  buf = w->buffer;
+  buf = w->contents;
   CHECK_BUFFER (buf);
   b = XBUFFER (buf);
 
   if (! NILP (update)
-      && (windows_or_buffers_changed || !w->window_end_valid)
+      && (windows_or_buffers_changed
+         || !w->window_end_valid
+         || b->clip_changed
+         || b->prevent_redisplay_optimizations_p
+         || window_outdated (w))
       && !noninteractive)
     {
       struct text_pos startp;
-      ptrdiff_t charpos = marker_position (w->start);
       struct it it;
       struct buffer *old_buffer = NULL;
       void *itdata = NULL;
@@ -1503,12 +1634,7 @@ if it isn't already recorded.  */)
          `-l' containing a call to `rmail' with subsequent other
          commands.  At the end, W->start happened to be BEG, while
          rmail had already narrowed the buffer.  */
-      if (charpos < BEGV)
-       SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
-      else if (charpos > ZV)
-       SET_TEXT_POS (startp, ZV, ZV_BYTE);
-      else
-       SET_TEXT_POS_FROM_MARKER (startp, w->start);
+      CLIP_TEXT_POS_FROM_MARKER (startp, w->start);
 
       itdata = bidi_shelve_cache ();
       start_display (&it, w, startp);
@@ -1522,7 +1648,7 @@ if it isn't already recorded.  */)
        set_buffer_internal (old_buffer);
     }
   else
-    XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
+    XSETINT (value, BUF_Z (b) - w->window_end_pos);
 
   return value;
 }
@@ -1539,7 +1665,7 @@ Return POS.  */)
 
   if (w == XWINDOW (selected_window))
     {
-      if (XBUFFER (w->buffer) == current_buffer)
+      if (XBUFFER (w->contents) == current_buffer)
        Fgoto_char (pos);
       else
        {
@@ -1547,17 +1673,17 @@ Return POS.  */)
 
          /* ... but here we want to catch type error before buffer change.  */
          CHECK_NUMBER_COERCE_MARKER (pos);
-         set_buffer_internal (XBUFFER (w->buffer));
+         set_buffer_internal (XBUFFER (w->contents));
          Fgoto_char (pos);
          set_buffer_internal (old_buffer);
        }
     }
   else
     {
-      set_marker_restricted (w->pointm, pos, w->buffer);
+      set_marker_restricted (w->pointm, pos, w->contents);
       /* We have to make sure that redisplay updates the window to show
         the new value of point.  */
-      ++windows_or_buffers_changed;
+      windows_or_buffers_changed = 25;
     }
 
   return pos;
@@ -1572,16 +1698,16 @@ overriding motion of point in order to display at this exact start.  */)
 {
   register struct window *w = decode_live_window (window);
 
-  set_marker_restricted (w->start, pos, w->buffer);
+  set_marker_restricted (w->start, pos, w->contents);
   /* This is not right, but much easier than doing what is right.  */
   w->start_at_line_beg = 0;
   if (NILP (noforce))
     w->force_start = 1;
   w->update_mode_line = 1;
-  w->last_modified = 0;
-  w->last_overlay_modified = 0;
-  if (!EQ (window, selected_window))
-    windows_or_buffers_changed++;
+  /* Bug#15957.  */
+  w->window_end_valid = 0;
+  if (w != XWINDOW (selected_window))
+    wset_redisplay (w);
 
   return pos;
 }
@@ -1599,12 +1725,13 @@ specifies the position of the last visible glyph in WINDOW.  POS
 defaults to point in WINDOW; WINDOW defaults to the selected window.
 
 If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
-return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
+the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
 where X and Y are the pixel coordinates relative to the top left corner
 of the window.  The remaining elements are omitted if the character after
 POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
-off-window at the top and bottom of the row, ROWH is the height of the
-display row, and VPOS is the row number (0-based) containing POS.  */)
+off-window at the top and bottom of the screen line ("row") containing
+POS, ROWH is the visible height of that row, and VPOS is the row number
+\(zero-based).  */)
   (Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
 {
   register struct window *w;
@@ -1616,7 +1743,7 @@ display row, and VPOS is the row number (0-based) containing POS.  */)
   int x, y;
 
   w = decode_live_window (window);
-  buf = XBUFFER (w->buffer);
+  buf = XBUFFER (w->contents);
   SET_TEXT_POS_FROM_MARKER (top, w->start);
 
   if (EQ (pos, Qt))
@@ -1685,15 +1812,15 @@ Return nil if window display is not up-to-date.  In that case, use
   if (noninteractive || w->pseudo_window_p)
     return Qnil;
 
-  CHECK_BUFFER (w->buffer);
-  b = XBUFFER (w->buffer);
+  CHECK_BUFFER (w->contents);
+  b = XBUFFER (w->contents);
 
   /* Fail if current matrix is not up-to-date.  */
   if (!w->window_end_valid
-      || current_buffer->clip_changed
-      || current_buffer->prevent_redisplay_optimizations_p
-      || w->last_modified < BUF_MODIFF (b)
-      || w->last_overlay_modified < BUF_OVERLAY_MODIFF (b))
+      || windows_or_buffers_changed
+      || b->clip_changed
+      || b->prevent_redisplay_optimizations_p
+      || window_outdated (w))
     return Qnil;
 
   if (NILP (line))
@@ -1912,9 +2039,9 @@ window_display_table (struct window *w)
 
   if (DISP_TABLE_P (w->display_table))
     dp = XCHAR_TABLE (w->display_table);
-  else if (BUFFERP (w->buffer))
+  else if (BUFFERP (w->contents))
     {
-      struct buffer *b = XBUFFER (w->buffer);
+      struct buffer *b = XBUFFER (w->contents);
 
       if (DISP_TABLE_P (BVAR (b, display_table)))
        dp = XCHAR_TABLE (BVAR (b, display_table));
@@ -1939,17 +2066,14 @@ WINDOW must be a live window and defaults to the selected one.  */)
 static void
 unshow_buffer (register struct window *w)
 {
-  Lisp_Object buf;
-  struct buffer *b;
+  Lisp_Object buf = w->contents;
+  struct buffer *b = XBUFFER (buf);
 
-  buf = w->buffer;
-  b = XBUFFER (buf);
-  if (b != XMARKER (w->pointm)->buffer)
-    emacs_abort ();
+  eassert (b == XMARKER (w->pointm)->buffer);
 
 #if 0
   if (w == XWINDOW (selected_window)
-      || ! EQ (buf, XWINDOW (selected_window)->buffer))
+      || ! EQ (buf, XWINDOW (selected_window)->contents))
     /* Do this except when the selected window's buffer
        is being removed from some other window.  */
 #endif
@@ -1965,14 +2089,14 @@ unshow_buffer (register struct window *w)
   /* Point in the selected window's buffer
      is actually stored in that buffer, and the window's pointm isn't used.
      So don't clobber point in that buffer.  */
-  if (! EQ (buf, XWINDOW (selected_window)->buffer)
+  if (! EQ (buf, XWINDOW (selected_window)->contents)
       /* Don't clobber point in current buffer either (this could be
         useful in connection with bug#12208).
       && XBUFFER (buf) != current_buffer  */
       /* This line helps to fix Horsley's testbug.el bug.  */
       && !(WINDOWP (BVAR (b, last_selected_window))
           && w != XWINDOW (BVAR (b, last_selected_window))
-          && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer)))
+          && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->contents)))
     temp_set_point_both (b,
                         clip_to_bounds (BUF_BEGV (b),
                                         marker_position (w->pointm),
@@ -2000,12 +2124,16 @@ replace_window (Lisp_Object old, Lisp_Object new, int setflag)
   if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
     fset_root_window (XFRAME (o->frame), new);
 
-   if (setflag)
-     {
-      wset_left_col (n, o->left_col);
-      wset_top_line (n, o->top_line);
-      wset_total_cols (n, o->total_cols);
-      wset_total_lines (n, o->total_lines);
+  if (setflag)
+    {
+      n->pixel_left = o->pixel_left;
+      n->pixel_top = o->pixel_top;
+      n->pixel_width = o->pixel_width;
+      n->pixel_height = o->pixel_height;
+      n->left_col = o->left_col;
+      n->top_line = o->top_line;
+      n->total_cols = o->total_cols;
+      n->total_lines = o->total_lines;
       wset_normal_cols (n, o->normal_cols);
       wset_normal_cols (o, make_float (1.0));
       wset_normal_lines (n, o->normal_lines);
@@ -2013,16 +2141,17 @@ replace_window (Lisp_Object old, Lisp_Object new, int setflag)
       n->desired_matrix = n->current_matrix = 0;
       n->vscroll = 0;
       memset (&n->cursor, 0, sizeof (n->cursor));
-      memset (&n->last_cursor, 0, sizeof (n->last_cursor));
       memset (&n->phys_cursor, 0, sizeof (n->phys_cursor));
-      n->phys_cursor_type = -1;
+      n->last_cursor_vpos = 0;
+#ifdef HAVE_WINDOW_SYSTEM
+      n->phys_cursor_type = NO_CURSOR;
       n->phys_cursor_width = -1;
+#endif
       n->must_be_updated_p = 0;
       n->pseudo_window_p = 0;
-      wset_window_end_vpos (n, make_number (0));
-      wset_window_end_pos (n, make_number (0));
+      n->window_end_vpos = 0;
+      n->window_end_pos = 0;
       n->window_end_valid = 0;
-      n->frozen_window_start_p = 0;
     }
 
   tem = o->next;
@@ -2037,13 +2166,8 @@ replace_window (Lisp_Object old, Lisp_Object new, int setflag)
 
   tem = o->parent;
   wset_parent (n, tem);
-  if (!NILP (tem))
-    {
-      if (EQ (XWINDOW (tem)->vchild, old))
-       wset_vchild (XWINDOW (tem), new);
-      if (EQ (XWINDOW (tem)->hchild, old))
-       wset_hchild (XWINDOW (tem), new);
-    }
+  if (!NILP (tem) && EQ (XWINDOW (tem)->contents, old))
+    wset_combination (XWINDOW (tem), XWINDOW (tem)->horizontal, new);
 }
 
 /* If window WINDOW and its parent window are iso-combined, merge
@@ -2062,22 +2186,19 @@ recombine_windows (Lisp_Object window)
   if (!NILP (parent) && NILP (w->combination_limit))
     {
       p = XWINDOW (parent);
-      if (((!NILP (p->vchild) && !NILP (w->vchild))
-          || (!NILP (p->hchild) && !NILP (w->hchild))))
+      if (WINDOWP (p->contents) && WINDOWP (w->contents)
+         && p->horizontal == w->horizontal)
        /* WINDOW and PARENT are both either a vertical or a horizontal
           combination.  */
        {
-         horflag = NILP (w->vchild);
-         child = horflag ? w->hchild : w->vchild;
+         horflag = WINDOW_HORIZONTAL_COMBINATION_P (w);
+         child = w->contents;
          c = XWINDOW (child);
 
          /* Splice WINDOW's children into its parent's children and
             assign new normal sizes.  */
          if (NILP (w->prev))
-           if (horflag)
-             wset_hchild (p, child);
-           else
-             wset_vchild (p, child);
+           wset_combination (p, horflag, child);
          else
            {
              wset_prev (c, w->prev);
@@ -2089,13 +2210,13 @@ recombine_windows (Lisp_Object window)
              wset_parent (c, parent);
 
              if (horflag)
-               wset_normal_cols (c,
-                                 make_float (XFLOATINT (c->total_cols)
-                                             / XFLOATINT (p->total_cols)));
+               wset_normal_cols
+                 (c, make_float ((double) c->pixel_width
+                                 / (double) p->pixel_width));
              else
-               wset_normal_lines (c,
-                                  make_float (XFLOATINT (c->total_lines)
-                                              / XFLOATINT (p->total_lines)));
+               wset_normal_lines
+                 (c, make_float ((double) c->pixel_height
+                                 / (double) p->pixel_height));
 
              if (NILP (c->next))
                {
@@ -2115,8 +2236,7 @@ recombine_windows (Lisp_Object window)
            }
 
          /* WINDOW can be deleted now.  */
-         wset_vchild (w, Qnil);
-         wset_hchild (w, Qnil);
+         wset_combination (w, 0, Qnil);
        }
     }
 }
@@ -2140,7 +2260,7 @@ delete_deletable_window (Lisp_Object window)
 static int
 add_window_to_list (struct window *w, void *user_data)
 {
-  Lisp_Object *list = (Lisp_Object *) user_data;
+  Lisp_Object *list = user_data;
   Lisp_Object window;
   XSETWINDOW (window, w);
   *list = Fcons (window, *list);
@@ -2152,7 +2272,7 @@ add_window_to_list (struct window *w, void *user_data)
    Vwindow_list is a list, return that list.  Otherwise, build a new
    list, cache it in Vwindow_list, and return that.  */
 
-static Lisp_Object
+Lisp_Object
 window_list (void)
 {
   if (!CONSP (Vwindow_list))
@@ -2195,14 +2315,15 @@ window_list (void)
                a window means search the frame that window belongs to,
                a frame means consider windows on that frame, only.  */
 
-static int
-candidate_window_p (Lisp_Object window, Lisp_Object owindow, Lisp_Object minibuf, Lisp_Object all_frames)
+static bool
+candidate_window_p (Lisp_Object window, Lisp_Object owindow,
+                   Lisp_Object minibuf, Lisp_Object all_frames)
 {
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
-  int candidate_p = 1;
+  bool candidate_p = 1;
 
-  if (!BUFFERP (w->buffer))
+  if (!BUFFERP (w->contents))
     candidate_p = 0;
   else if (MINI_WINDOW_P (w)
            && (EQ (minibuf, Qlambda)
@@ -2542,7 +2663,7 @@ enum window_loop
   GET_BUFFER_WINDOW,               /* Arg is buffer */
   REPLACE_BUFFER_IN_WINDOWS_SAFELY, /* Arg is buffer */
   REDISPLAY_BUFFER_WINDOWS,        /* Arg is buffer */
-  CHECK_ALL_WINDOWS
+  CHECK_ALL_WINDOWS                 /* Arg is ignored */
 };
 
 static Lisp_Object
@@ -2606,7 +2727,7 @@ window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frame
        switch (type)
          {
          case GET_BUFFER_WINDOW:
-           if (EQ (w->buffer, obj)
+           if (EQ (w->contents, obj)
                /* Don't find any minibuffer window except the one that
                   is currently in use.  */
                && (MINI_WINDOW_P (w) ? EQ (window, minibuf_window) : 1))
@@ -2630,39 +2751,48 @@ window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frame
          case REPLACE_BUFFER_IN_WINDOWS_SAFELY:
            /* We could simply check whether the buffer shown by window
               is live, and show another buffer in case it isn't.  */
-           if (EQ (w->buffer, obj))
+           if (EQ (w->contents, obj))
              {
                /* Undedicate WINDOW.  */
                wset_dedicated (w, Qnil);
                /* Make WINDOW show the buffer returned by
                   other_buffer_safely, don't run any hooks.  */
                set_window_buffer
-                 (window, other_buffer_safely (w->buffer), 0, 0);
+                 (window, other_buffer_safely (w->contents), 0, 0);
                /* If WINDOW is the selected window, make its buffer
                   current.  But do so only if the window shows the
                   current buffer (Bug#6454).  */
                if (EQ (window, selected_window)
-                   && XBUFFER (w->buffer) == current_buffer)
-                 Fset_buffer (w->buffer);
+                   && XBUFFER (w->contents) == current_buffer)
+                 Fset_buffer (w->contents);
              }
            break;
 
          case REDISPLAY_BUFFER_WINDOWS:
-           if (EQ (w->buffer, obj))
+           if (EQ (w->contents, obj))
              {
                mark_window_display_accurate (window, 0);
                w->update_mode_line = 1;
                XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
-               ++update_mode_lines;
+               update_mode_lines = 27;
                best_window = window;
              }
            break;
 
-           /* Check for a window that has a killed buffer.  */
+           /* Check for a leaf window that has a killed buffer
+              or broken markers.  */
          case CHECK_ALL_WINDOWS:
-           if (! NILP (w->buffer)
-               && !BUFFER_LIVE_P (XBUFFER (w->buffer)))
-             emacs_abort ();
+           if (BUFFERP (w->contents))
+             {
+               struct buffer *b = XBUFFER (w->contents);
+
+               if (!BUFFER_LIVE_P (b))
+                 emacs_abort ();
+               if (!MARKERP (w->start) || XMARKER (w->start)->buffer != b)
+                 emacs_abort ();
+               if (!MARKERP (w->pointm) || XMARKER (w->pointm)->buffer != b)
+                 emacs_abort ();
+             }
            break;
 
          case WINDOW_LOOP_UNUSED:
@@ -2717,9 +2847,16 @@ selected frame and no others.  */)
 }
 
 static Lisp_Object
-resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore)
+resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore, Lisp_Object pixelwise)
+{
+  return call5 (Qwindow_resize_root_window, window, delta, horizontal, ignore, pixelwise);
+}
+
+
+static Lisp_Object
+window_pixel_to_total (Lisp_Object frame, Lisp_Object horizontal)
 {
-  return call4 (Qwindow_resize_root_window, window, delta, horizontal, ignore);
+  return call2(Qwindow_pixel_to_total, frame, horizontal);
 }
 
 
@@ -2779,12 +2916,12 @@ window-start value is reasonable when this function is called.  */)
   else if (MINI_WINDOW_P (w)) /* && top > 0) */
     error ("Can't expand minibuffer to full frame");
 
-  if (!NILP (w->buffer))
+  if (BUFFERP (w->contents))
     {
       startpos = marker_position (w->start);
       startbyte = marker_byte_position (w->start);
-      top = WINDOW_TOP_EDGE_LINE (w)
-       - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+      top = (WINDOW_TOP_EDGE_LINE (w)
+            - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w))));
       /* Make sure WINDOW is the frame's selected window.  */
       if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
        {
@@ -2828,7 +2965,7 @@ window-start value is reasonable when this function is called.  */)
   block_input ();
   if (!FRAME_INITIAL_P (f))
     {
-        Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+      Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
       /* We are going to free the glyph matrices of WINDOW, and with
         that we might lose any information about glyph rows that have
@@ -2838,33 +2975,35 @@ window-start value is reasonable when this function is called.  */)
         frame's up-to-date hook that mouse highlight was overwritten,
         so that it will arrange for redisplaying the highlight.  */
       if (EQ (hlinfo->mouse_face_window, window))
-       {
-         hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
-         hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
-         hlinfo->mouse_face_window = Qnil;
-       }
+       reset_mouse_highlight (hlinfo);
     }
   free_window_matrices (r);
 
-  windows_or_buffers_changed++;
+  windows_or_buffers_changed = 27;
   Vwindow_list = Qnil;
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
   resize_failed = 0;
 
-  if (NILP (w->buffer))
+  if (!WINDOW_LEAF_P (w))
     {
       /* Resize child windows vertically.  */
-      XSETINT (delta, XINT (r->total_lines)
-              - XINT (w->total_lines));
-      wset_top_line (w, r->top_line);
-      resize_root_window (window, delta, Qnil, Qnil);
+      XSETINT (delta, r->pixel_height - w->pixel_height);
+      w->pixel_top = r->pixel_top;
+      w->top_line = r->top_line;
+      resize_root_window (window, delta, Qnil, Qnil, Qt);
       if (window_resize_check (w, 0))
-       window_resize_apply (w, 0);
+       {
+         window_resize_apply (w, 0);
+         window_pixel_to_total (w->frame, Qnil);
+       }
       else
        {
-         resize_root_window (window, delta, Qnil, Qt);
+         resize_root_window (window, delta, Qnil, Qt, Qt);
          if (window_resize_check (w, 0))
-           window_resize_apply (w, 0);
+           {
+             window_resize_apply (w, 0);
+             window_pixel_to_total (w->frame, Qnil);
+           }
          else
            resize_failed = 1;
        }
@@ -2872,18 +3011,23 @@ window-start value is reasonable when this function is called.  */)
       /* Resize child windows horizontally.  */
       if (!resize_failed)
        {
-         wset_left_col (w, r->left_col);
-         XSETINT (delta,
-                  XINT (r->total_cols) - XINT (w->total_cols));
-         wset_left_col (w, r->left_col);
-         resize_root_window (window, delta, Qt, Qnil);
+         w->left_col = r->left_col;
+         w->pixel_left = r->pixel_left;
+         XSETINT (delta, r->pixel_width - w->pixel_width);
+         resize_root_window (window, delta, Qt, Qnil, Qt);
          if (window_resize_check (w, 1))
-           window_resize_apply (w, 1);
+           {
+             window_resize_apply (w, 1);
+             window_pixel_to_total (w->frame, Qt);
+           }
          else
            {
-             resize_root_window (window, delta, Qt, Qt);
+             resize_root_window (window, delta, Qt, Qt, Qt);
              if (window_resize_check (w, 1))
-               window_resize_apply (w, 1);
+               {
+                 window_resize_apply (w, 1);
+                 window_pixel_to_total (w->frame, Qt);
+               }
              else
                resize_failed = 1;
            }
@@ -2913,28 +3057,21 @@ window-start value is reasonable when this function is called.  */)
       sibling = w->next;
       s = XWINDOW (sibling);
       wset_prev (s, Qnil);
-      if (!NILP (XWINDOW (w->parent)->vchild))
-       wset_vchild (XWINDOW (w->parent), sibling);
-      else
-       wset_hchild (XWINDOW (w->parent), sibling);
+      wset_combination (XWINDOW (w->parent),
+                       XWINDOW (w->parent)->horizontal, sibling);
     }
 
   /* Delete ROOT and all child windows of ROOT.  */
-  if (!NILP (r->vchild))
-    {
-      delete_all_child_windows (r->vchild);
-      wset_vchild (r, Qnil);
-    }
-  else if (!NILP (r->hchild))
+  if (WINDOWP (r->contents))
     {
-      delete_all_child_windows (r->hchild);
-      wset_hchild (r, Qnil);
+      delete_all_child_windows (r->contents);
+      wset_combination (r, 0, Qnil);
     }
 
   replace_window (root, window, 1);
 
-  /* This must become SWINDOW anyway ....... */
-  if (!NILP (w->buffer) && !resize_failed)
+  /* This must become SWINDOW anyway .......  */
+  if (BUFFERP (w->contents) && !resize_failed)
     {
       /* Try to minimize scrolling, by setting the window start to the
         point will cause the text at the old window start to be at the
@@ -2943,18 +3080,18 @@ window-start value is reasonable when this function is called.  */)
         when the display is not current, due to typeahead).  */
       new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
       if (new_top != top
-         && startpos >= BUF_BEGV (XBUFFER (w->buffer))
-         && startpos <= BUF_ZV (XBUFFER (w->buffer)))
+         && startpos >= BUF_BEGV (XBUFFER (w->contents))
+         && startpos <= BUF_ZV (XBUFFER (w->contents)))
        {
          struct position pos;
          struct buffer *obuf = current_buffer;
 
-         Fset_buffer (w->buffer);
+         Fset_buffer (w->contents);
          /* This computation used to temporarily move point, but that
             can have unwanted side effects due to text properties.  */
          pos = *vmotion (startpos, startbyte, -top, w);
 
-         set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+         set_marker_both (w->start, w->contents, pos.bufpos, pos.bytepos);
          w->window_end_valid = 0;
          w->start_at_line_beg = (pos.bytepos == BEGV_BYTE
                                    || FETCH_BYTE (pos.bytepos - 1) == '\n');
@@ -2966,7 +3103,7 @@ window-start value is reasonable when this function is called.  */)
        }
     }
 
-  adjust_glyphs (f);
+  adjust_frame_glyphs (f);
   unblock_input ();
 
   run_window_configuration_change_hook (f);
@@ -2999,27 +3136,46 @@ replace_buffer_in_windows_safely (Lisp_Object buffer)
     }
 }
 
-/* If *ROWS or *COLS are too small a size for FRAME, set them to the
-   minimum allowable size.  */
+/* If *HEIGHT or *WIDTH are too small a size for FRAME, set them to the
+   minimum allowable size.  PIXELWISE means interpret these as pixel
+   sizes.  */
 
 void
-check_frame_size (FRAME_PTR frame, int *rows, int *cols)
+check_frame_size (struct frame *frame, int *width, int *height, bool pixelwise)
 {
   /* For height, we have to see:
      how many windows the frame has at minimum (one or two),
      and whether it has a menu bar or other special stuff at the top.  */
-  int min_height
-    = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
-       ? MIN_SAFE_WINDOW_HEIGHT
-       : 2 * MIN_SAFE_WINDOW_HEIGHT);
+  if (pixelwise)
+    {
+      int min_height = MIN_SAFE_WINDOW_HEIGHT * FRAME_LINE_HEIGHT (frame);
+      int min_width = MIN_SAFE_WINDOW_WIDTH * FRAME_COLUMN_WIDTH (frame);
+
+      if (!FRAME_MINIBUF_ONLY_P (frame) && FRAME_HAS_MINIBUF_P (frame))
+       min_height = 2 * min_height;
+
+      min_height += FRAME_TOP_MARGIN_HEIGHT (frame);
+
+      if (*height < min_height)
+       *height = min_height;
+      if (*width < min_width)
+       *width = min_width;
+    }
+  else
+    {
+      int min_height
+       = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
+          ? MIN_SAFE_WINDOW_HEIGHT
+          : 2 * MIN_SAFE_WINDOW_HEIGHT);
 
-  if (FRAME_TOP_MARGIN (frame) > 0)
-    min_height += FRAME_TOP_MARGIN (frame);
+      if (FRAME_TOP_MARGIN (frame) > 0)
+       min_height += FRAME_TOP_MARGIN (frame);
 
-  if (*rows < min_height)
-    *rows = min_height;
-  if (*cols  < MIN_SAFE_WINDOW_WIDTH)
-    *cols = MIN_SAFE_WINDOW_WIDTH;
+      if (*height < min_height)
+       *height = min_height;
+      if (*width  < MIN_SAFE_WINDOW_WIDTH)
+       *width = MIN_SAFE_WINDOW_WIDTH;
+    }
 }
 
 /* Adjust the margins of window W if text area is too small.
@@ -3029,34 +3185,37 @@ check_frame_size (FRAME_PTR frame, int *rows, int *cols)
 static int
 adjust_window_margins (struct window *w)
 {
-  int box_cols = (WINDOW_TOTAL_COLS (w)
-                 - WINDOW_FRINGE_COLS (w)
-                 - WINDOW_SCROLL_BAR_COLS (w));
-  int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
-                    + WINDOW_RIGHT_MARGIN_COLS (w));
+  int box_width = (WINDOW_PIXEL_WIDTH (w)
+                  - WINDOW_FRINGES_WIDTH (w)
+                  - WINDOW_SCROLL_BAR_AREA_WIDTH (w));
+  int margin_width = WINDOW_MARGINS_WIDTH (w);
 
-  if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
+  if (box_width - margin_width >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
     return 1;
 
-  if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
+  if (margin_width < 0 || box_width < MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
     return 0;
-
-  /* Window's text area is too narrow, but reducing the window
-     margins will fix that.  */
-  margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
-  if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
+  else
+    /* Window's text area is too narrow, but reducing the window
+       margins will fix that.  */
     {
-      if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
+      int unit = WINDOW_FRAME_COLUMN_WIDTH (w);
+
+      margin_width = box_width - MIN_SAFE_WINDOW_PIXEL_WIDTH (w);
+
+      if (WINDOW_RIGHT_MARGIN_WIDTH (w) > 0)
        {
-         wset_left_margin_cols (w, make_number (margin_cols / 2));
-         wset_right_margin_cols (w, make_number (margin_cols / 2));
+         if (WINDOW_LEFT_MARGIN_WIDTH (w) > 0)
+           w->left_margin_cols = w->right_margin_cols =
+             margin_width / (2 * unit);
+         else
+           w->right_margin_cols = margin_width / unit;
        }
       else
-       wset_right_margin_cols (w, make_number (margin_cols));
+       w->left_margin_cols = margin_width / unit;
+
+      return 1;
     }
-  else
-    wset_left_margin_cols (w, make_number (margin_cols));
-  return 1;
 }
 \f
 /* The following three routines are needed for running a window's
@@ -3069,18 +3228,18 @@ run_funs (Lisp_Object funs)
       call0 (XCAR (funs));
 }
 
-static Lisp_Object
+static void
 select_window_norecord (Lisp_Object window)
 {
-  return WINDOW_LIVE_P (window)
-    ? Fselect_window (window, Qt) : selected_window;
+  if (WINDOW_LIVE_P (window))
+    Fselect_window (window, Qt);
 }
 
-static Lisp_Object
+static void
 select_frame_norecord (Lisp_Object frame)
 {
-  return FRAME_LIVE_P (XFRAME (frame))
-    ? Fselect_frame (frame, Qt) : selected_frame;
+  if (FRAME_LIVE_P (XFRAME (frame)))
+    Fselect_frame (frame, Qt);
 }
 
 void
@@ -3103,7 +3262,7 @@ run_window_configuration_change_hook (struct frame *f)
 
   if (SELECTED_FRAME () != f)
     {
-      record_unwind_protect (select_frame_norecord, Fselected_frame ());
+      record_unwind_protect (select_frame_norecord, selected_frame);
       select_frame_norecord (frame);
     }
 
@@ -3118,7 +3277,7 @@ run_window_configuration_change_hook (struct frame *f)
                                      buffer)))
          {
            ptrdiff_t inner_count = SPECPDL_INDEX ();
-           record_unwind_protect (select_window_norecord, Fselected_window ());
+           record_unwind_protect (select_window_norecord, selected_window);
            select_window_norecord (window);
            run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
                                           buffer));
@@ -3141,11 +3300,23 @@ If FRAME is omitted or nil, it defaults to the selected frame.  */)
   return Qnil;
 }
 
-/* Make WINDOW display BUFFER as its contents.  RUN_HOOKS_P non-zero
-   means it's allowed to run hooks.  See make_frame for a case where
-   it's not allowed.  KEEP_MARGINS_P non-zero means that the current
-   margins, fringes, and scroll-bar settings of the window are not
-   reset from the buffer's local settings.  */
+DEFUN ("run-window-scroll-functions", Frun_window_scroll_functions,
+       Srun_window_scroll_functions, 0, 1, 0,
+       doc: /* Run `window-scroll-functions' for WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
+{
+  if (! NILP (Vwindow_scroll_functions))
+    run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                         Fmarker_position (decode_live_window (window)->start));
+  return Qnil;
+}
+
+/* Make WINDOW display BUFFER.  RUN_HOOKS_P non-zero means it's allowed
+   to run hooks.  See make_frame for a case where it's not allowed.
+   KEEP_MARGINS_P non-zero means that the current margins, fringes, and
+   scroll-bar settings of the window are not reset from the buffer's
+   local settings.  */
 
 void
 set_window_buffer (Lisp_Object window, Lisp_Object buffer,
@@ -3154,7 +3325,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
   struct window *w = XWINDOW (window);
   struct buffer *b = XBUFFER (buffer);
   ptrdiff_t count = SPECPDL_INDEX ();
-  int samebuf = EQ (buffer, w->buffer);
+  bool samebuf = EQ (buffer, w->contents);
 
   wset_buffer (w, buffer);
 
@@ -3169,9 +3340,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
     bset_display_count (b, make_number (XINT (BVAR (b, display_count)) + 1));
   bset_display_time (b, Fcurrent_time ());
 
-  wset_window_end_pos (w, make_number (0));
-  wset_window_end_vpos (w, make_number (0));
-  memset (&w->last_cursor, 0, sizeof w->last_cursor);
+  w->window_end_pos = 0;
+  w->window_end_vpos = 0;
+  w->last_cursor_vpos = 0;
 
   if (!(keep_margins_p && samebuf))
     { /* If we're not actually changing the buffer, don't reset hscroll and
@@ -3190,12 +3361,10 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
                             buffer);
       w->start_at_line_beg = 0;
       w->force_start = 0;
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
     }
   /* Maybe we could move this into the `if' but it's not obviously safe and
      I doubt it's worth the trouble.  */
-  windows_or_buffers_changed++;
+  windows_or_buffers_changed = 28;
 
   /* We must select BUFFER for running the window-scroll-functions.  */
   /* We can't check ! NILP (Vwindow_scroll_functions) here
@@ -3211,28 +3380,14 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
   if (!keep_margins_p)
     {
       /* Set left and right marginal area width etc. from buffer.  */
-
-      /* This may call adjust_window_margins three times, so
-        temporarily disable window margins.  */
-      Lisp_Object save_left = w->left_margin_cols;
-      Lisp_Object save_right = w->right_margin_cols;
-
-      wset_left_margin_cols (w, Qnil);
-      wset_right_margin_cols (w, Qnil);
-
-      Fset_window_fringes (window,
-                          BVAR (b, left_fringe_width), BVAR (b, right_fringe_width),
-                          BVAR (b, fringes_outside_margins));
-
-      Fset_window_scroll_bars (window,
-                              BVAR (b, scroll_bar_width),
-                              BVAR (b, vertical_scroll_bar_type), Qnil);
-
-      wset_left_margin_cols (w, save_left);
-      wset_right_margin_cols (w, save_right);
-
-      Fset_window_margins (window,
-                          BVAR (b, left_margin_cols), BVAR (b, right_margin_cols));
+      set_window_fringes (w, BVAR (b, left_fringe_width),
+                         BVAR (b, right_fringe_width),
+                         BVAR (b, fringes_outside_margins));
+      set_window_scroll_bars (w, BVAR (b, scroll_bar_width),
+                             BVAR (b, vertical_scroll_bar_type), Qnil);
+      set_window_margins (w, BVAR (b, left_margin_cols),
+                         BVAR (b, right_margin_cols));
+      apply_window_adjustment (w);
     }
 
   if (run_hooks_p)
@@ -3240,14 +3395,15 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
       if (! NILP (Vwindow_scroll_functions))
        run_hook_with_args_2 (Qwindow_scroll_functions, window,
                              Fmarker_position (w->start));
-      run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
+      if (!samebuf)
+       run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
     }
 
   unbind_to (count, Qnil);
 }
 
 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
-       doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
+       doc: /* Make WINDOW display BUFFER-OR-NAME.
 WINDOW must be a live window and defaults to the selected one.
 BUFFER-OR-NAME must be a buffer or the name of an existing buffer.
 
@@ -3273,7 +3429,7 @@ This function runs `window-scroll-functions' before running
   if (!BUFFER_LIVE_P (XBUFFER (buffer)))
     error ("Attempt to display deleted buffer");
 
-  tem = w->buffer;
+  tem = w->contents;
   if (NILP (tem))
     error ("Window is deleted");
   else
@@ -3316,8 +3472,8 @@ displaying that buffer.  */)
 {
   if (NILP (object))
     {
-      windows_or_buffers_changed++;
-      update_mode_lines++;
+      windows_or_buffers_changed = 29;
+      update_mode_lines = 28;
       return Qt;
     }
 
@@ -3326,9 +3482,9 @@ displaying that buffer.  */)
       struct window *w = XWINDOW (object);
       mark_window_display_accurate (object, 0);
       w->update_mode_line = 1;
-      if (BUFFERP (w->buffer))
-       XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
-      ++update_mode_lines;
+      if (BUFFERP (w->contents))
+       XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1;
+      update_mode_lines = 29;
       return Qt;
     }
 
@@ -3368,10 +3524,8 @@ temp_output_buffer_show (register Lisp_Object buf)
 
   if (!NILP (Vtemp_buffer_show_function))
     call1 (Vtemp_buffer_show_function, buf);
-  else
+  else if (WINDOW_LIVE_P (window = display_buffer (buf, Qnil, Qnil)))
     {
-      window = display_buffer (buf, Qnil, Qnil);
-
       if (!EQ (XWINDOW (window)->frame, selected_frame))
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
       Vminibuf_scroll_window = window;
@@ -3393,10 +3547,10 @@ temp_output_buffer_show (register Lisp_Object buf)
            Note: Both Fselect_window and select_window_norecord may
            set-buffer to the buffer displayed in the window,
            so we need to save the current buffer.  --stef  */
-        record_unwind_protect (Fset_buffer, prev_buffer);
+        record_unwind_protect (restore_buffer, prev_buffer);
         record_unwind_protect (select_window_norecord, prev_window);
         Fselect_window (window, Qt);
-        Fset_buffer (w->buffer);
+        Fset_buffer (w->contents);
         Frun_hooks (1, &Qtemp_buffer_show_hook);
         unbind_to (count, Qnil);
       }
@@ -3417,21 +3571,22 @@ make_parent_window (Lisp_Object window, bool horflag)
   memcpy ((char *) p + sizeof (struct vectorlike_header),
          (char *) o + sizeof (struct vectorlike_header),
          word_size * VECSIZE (struct window));
-  /* P's buffer slot may change from nil to a buffer.  */
+  /* P's buffer slot may change from nil to a buffer...  */
   adjust_window_count (p, 1);
   XSETWINDOW (parent, p);
 
+  p->sequence_number = ++sequence_number;
+
   replace_window (window, parent, 1);
 
   wset_next (o, Qnil);
   wset_prev (o, Qnil);
   wset_parent (o, parent);
-
-  wset_hchild (p, horflag ? window : Qnil);
-  wset_vchild (p, horflag ? Qnil : window);
+  /* ...but now P becomes an internal window.  */
   wset_start (p, Qnil);
   wset_pointm (p, Qnil);
   wset_buffer (p, Qnil);
+  wset_combination (p, horflag, window);
   wset_combination_limit (p, Qnil);
   wset_window_parameters (p, Qnil);
 }
@@ -3446,19 +3601,14 @@ make_window (void)
   w = allocate_window ();
   /* Initialize Lisp data.  Note that allocate_window initializes all
      Lisp data to nil, so do it only for slots which should not be nil.  */
-  wset_left_col (w, make_number (0));
-  wset_top_line (w, make_number (0));
-  wset_total_lines (w, make_number (0));
-  wset_total_cols (w, make_number (0));
   wset_normal_lines (w, make_float (1.0));
   wset_normal_cols (w, make_float (1.0));
   wset_new_total (w, make_number (0));
   wset_new_normal (w, make_number (0));
+  wset_new_pixel (w, make_number (0));
   wset_start (w, Fmake_marker ());
   wset_pointm (w, Fmake_marker ());
   wset_vertical_scroll_bar_type (w, Qt);
-  wset_window_end_pos (w, make_number (0));
-  wset_window_end_vpos (w, make_number (0));
   /* These Lisp fields are marked specially so they're not set to nil by
      allocate_window.  */
   wset_prev_buffers (w, Qnil);
@@ -3467,8 +3617,14 @@ make_window (void)
   /* Initialize non-Lisp data.  Note that allocate_window zeroes out all
      non-Lisp data, so do it only for slots which should not be zero.  */
   w->nrows_scale_factor = w->ncols_scale_factor = 1;
-  w->phys_cursor_type = -1;
+  w->left_fringe_width = w->right_fringe_width = -1;
+  w->mode_line_height = w->header_line_height = -1;
+#ifdef HAVE_WINDOW_SYSTEM
+  w->phys_cursor_type = NO_CURSOR;
   w->phys_cursor_width = -1;
+#endif
+  w->sequence_number = ++sequence_number;
+  w->scroll_bar_width = -1;
   w->column_number_displayed = -1;
 
   /* Reset window_list.  */
@@ -3478,6 +3634,30 @@ make_window (void)
   return window;
 }
 \f
+DEFUN ("set-window-new-pixel", Fset_window_new_pixel, Sset_window_new_pixel, 2, 3, 0,
+       doc: /* Set new pixel size of WINDOW to SIZE.
+WINDOW must be a valid window and defaults to the selected one.
+Return SIZE.
+
+Optional argument ADD non-nil means add SIZE to the new pixel size of
+WINDOW and return the sum.
+
+Note: This function does not operate on any child windows of WINDOW.  */)
+  (Lisp_Object window, Lisp_Object size, Lisp_Object add)
+{
+  struct window *w = decode_valid_window (window);
+  EMACS_INT size_max = (min (INT_MAX, MOST_POSITIVE_FIXNUM)
+                       - (NILP (add) ? 0 : XINT (w->new_pixel)));
+
+  CHECK_RANGED_INTEGER (size, 0, size_max);
+  if (NILP (add))
+    wset_new_pixel (w, size);
+  else
+    wset_new_pixel (w, make_number (XINT (w->new_pixel) + XINT (size)));
+
+  return w->new_pixel;
+}
+
 DEFUN ("set-window-new-total", Fset_window_new_total, Sset_window_new_total, 2, 3, 0,
        doc: /* Set new total size of WINDOW to SIZE.
 WINDOW must be a valid window and defaults to the selected one.
@@ -3512,8 +3692,8 @@ Note: This function does not operate on any child windows of WINDOW.  */)
   return size;
 }
 
-/* Return 1 if setting w->total_lines (w->total_cols if HORFLAG is
-   non-zero) to w->new_total would result in correct heights (widths)
+/* Return 1 if setting w->pixel_height (w->pixel_width if HORFLAG is
+   non-zero) to w->new_pixel would result in correct heights (widths)
    for window W and recursively all child windows of W.
 
    Note: This function does not check any of `window-fixed-size-p',
@@ -3522,67 +3702,78 @@ Note: This function does not operate on any child windows of WINDOW.  */)
 static int
 window_resize_check (struct window *w, bool horflag)
 {
+  struct frame *f = XFRAME (w->frame);
   struct window *c;
 
-  if (!NILP (w->vchild))
+  if (WINDOW_VERTICAL_COMBINATION_P (w))
     /* W is a vertical combination.  */
     {
-      c = XWINDOW (w->vchild);
+      c = XWINDOW (w->contents);
       if (horflag)
        /* All child windows of W must have the same width as W.  */
        {
          while (c)
            {
-             if ((XINT (c->new_total) != XINT (w->new_total))
+             if (XINT (c->new_pixel) != XINT (w->new_pixel)
                  || !window_resize_check (c, horflag))
                return 0;
+
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
+
          return 1;
        }
       else
        /* The sum of the heights of the child windows of W must equal
           W's height.  */
        {
-         int sum_of_sizes = 0;
+         int sum_of_pixels = 0;
+
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
-             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+
+             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
-         return (sum_of_sizes == XINT (w->new_total));
+
+         return (sum_of_pixels == XINT (w->new_pixel));
        }
     }
-  else if (!NILP (w->hchild))
+  else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
     /* W is a horizontal combination.  */
     {
-      c = XWINDOW (w->hchild);
+      c = XWINDOW (w->contents);
       if (horflag)
        /* The sum of the widths of the child windows of W must equal W's
           width.  */
        {
-         int sum_of_sizes = 0;
+         int sum_of_pixels = 0;
+
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
-             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+
+             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
-         return (sum_of_sizes == XINT (w->new_total));
+
+         return (sum_of_pixels == XINT (w->new_pixel));
        }
       else
        /* All child windows of W must have the same height as W.  */
        {
          while (c)
            {
-             if ((XINT (c->new_total) != XINT (w->new_total))
+             if (XINT (c->new_pixel) != XINT (w->new_pixel)
                  || !window_resize_check (c, horflag))
                return 0;
+
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
+
          return 1;
        }
     }
@@ -3590,12 +3781,15 @@ window_resize_check (struct window *w, bool horflag)
     /* A leaf window.  Make sure it's not too small.  The following
        hardcodes the values of `window-safe-min-width' (2) and
        `window-safe-min-height' (1) which are defined in window.el.  */
-    return XINT (w->new_total) >= (horflag ? 2 : 1);
+    return (XINT (w->new_pixel) >= (horflag
+                                   ? (2 * FRAME_COLUMN_WIDTH (f))
+                                   : FRAME_LINE_HEIGHT (f)));
 }
 
-/* Set w->total_lines (w->total_cols if HORIZONTAL is non-zero) to
-   w->new_total for window W and recursively all child windows of W.
-   Also calculate and assign the new vertical (horizontal) start
+
+/* Set w->pixel_height (w->pixel_height if HORIZONTAL is non-zero) to
+   w->new_pixel for window W and recursively all child windows of W.
+   Also calculate and assign the new vertical (horizontal) pixel start
    positions of each of these windows.
 
    This function does not perform any error checks.  Make sure you have
@@ -3604,73 +3798,153 @@ static void
 window_resize_apply (struct window *w, bool horflag)
 {
   struct window *c;
-  int pos;
+  int edge;
+  int unit = (horflag
+             ? FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w))
+             : FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)));
 
   /* Note: Assigning new_normal requires that the new total size of the
      parent window has been set *before*.  */
   if (horflag)
     {
-      wset_total_cols (w, w->new_total);
+      w->pixel_width = XFASTINT (w->new_pixel);
+      w->total_cols = w->pixel_width / unit;
       if (NUMBERP (w->new_normal))
        wset_normal_cols (w, w->new_normal);
 
-      pos = XINT (w->left_col);
+      edge = w->pixel_left;
     }
   else
     {
-      wset_total_lines (w, w->new_total);
+      w->pixel_height = XFASTINT (w->new_pixel);
+      w->total_lines = w->pixel_height / unit;
       if (NUMBERP (w->new_normal))
        wset_normal_lines (w, w->new_normal);
 
-      pos = XINT (w->top_line);
+      edge = w->pixel_top;
     }
 
-  if (!NILP (w->vchild))
+  if (WINDOW_VERTICAL_COMBINATION_P (w))
     /* W is a vertical combination.  */
     {
-      c = XWINDOW (w->vchild);
+      c = XWINDOW (w->contents);
       while (c)
        {
          if (horflag)
-           wset_left_col (c, make_number (pos));
+           {
+             c->pixel_left = edge;
+             c->left_col = edge / unit;
+           }
          else
-           wset_top_line (c, make_number (pos));
+           {
+             c->pixel_top = edge;
+             c->top_line = edge / unit;
+           }
          window_resize_apply (c, horflag);
          if (!horflag)
-           pos = pos + XINT (c->total_lines);
+           edge = edge + c->pixel_height;
+
          c = NILP (c->next) ? 0 : XWINDOW (c->next);
        }
     }
-  else if (!NILP (w->hchild))
+  else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
     /* W is a horizontal combination.  */
     {
-      c = XWINDOW (w->hchild);
+      c = XWINDOW (w->contents);
       while (c)
        {
          if (horflag)
-           wset_left_col (c, make_number (pos));
+           {
+             c->pixel_left = edge;
+             c->left_col = edge / unit;
+           }
          else
-           wset_top_line (c, make_number (pos));
+           {
+             c->pixel_top = edge;
+             c->top_line = edge / unit;
+           }
+
          window_resize_apply (c, horflag);
          if (horflag)
-           pos = pos + XINT (c->total_cols);
+           edge = edge + c->pixel_width;
+
          c = NILP (c->next) ? 0 : XWINDOW (c->next);
        }
     }
-
-  /* Clear out some redisplay caches.  */
-  w->last_modified = 0;
-  w->last_overlay_modified = 0;
+  else
+    /* Bug#15957.  */
+    w->window_end_valid = 0;
 }
 
 
-DEFUN ("window-resize-apply", Fwindow_resize_apply, Swindow_resize_apply, 0, 2, 0,
-       doc: /* Apply requested size values for window-tree of FRAME.
-If FRAME is omitted or nil, it defaults to the selected frame.
-
-Optional argument HORIZONTAL omitted or nil means apply requested
-height values.  HORIZONTAL non-nil means apply requested width values.
-
+/* Set w->total_lines (w->total_cols if HORIZONTAL is non-zero) to
+   w->new_total for window W and recursively all child windows of W.
+   Also calculate and assign the new vertical (horizontal) start
+   positions of each of these windows.  */
+static void
+window_resize_apply_total (struct window *w, bool horflag)
+{
+  struct window *c;
+  int edge;
+
+  /* Note: Assigning new_normal requires that the new total size of the
+     parent window has been set *before*.  */
+  if (horflag)
+    {
+      w->total_cols = XFASTINT (w->new_total);
+      edge = w->left_col;
+    }
+  else
+    {
+      w->total_lines = XFASTINT (w->new_total);
+      edge = w->top_line;
+    }
+
+  if (WINDOW_VERTICAL_COMBINATION_P (w))
+    /* W is a vertical combination.  */
+    {
+      c = XWINDOW (w->contents);
+      while (c)
+       {
+         if (horflag)
+           c->left_col = edge;
+         else
+           c->top_line = edge;
+
+         window_resize_apply_total (c, horflag);
+         if (!horflag)
+           edge = edge + c->total_lines;
+
+         c = NILP (c->next) ? 0 : XWINDOW (c->next);
+       }
+    }
+  else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
+    /* W is a horizontal combination.  */
+    {
+      c = XWINDOW (w->contents);
+      while (c)
+       {
+         if (horflag)
+           c->left_col = edge;
+         else
+           c->top_line = edge;
+
+         window_resize_apply_total (c, horflag);
+         if (horflag)
+           edge = edge + c->total_cols;
+
+         c = NILP (c->next) ? 0 : XWINDOW (c->next);
+       }
+    }
+}
+
+DEFUN ("window-resize-apply", Fwindow_resize_apply, Swindow_resize_apply, 0, 2, 0,
+       doc: /* Apply requested size values for window-tree of FRAME.
+If FRAME is omitted or nil, it defaults to the selected frame.
+
+Optional argument HORIZONTAL omitted or nil means apply requested
+height values.  HORIZONTAL non-nil means apply requested width values.
+
 This function checks whether the requested values sum up to a valid
 window layout, recursively assigns the new sizes of all child windows
 and calculates and assigns the new start positions of these windows.
@@ -3685,20 +3959,44 @@ be applied on the Elisp level.  */)
   bool horflag = !NILP (horizontal);
 
   if (!window_resize_check (r, horflag)
-      || ! EQ (r->new_total,
-              (horflag ? r->total_cols : r->total_lines)))
+      || (XINT (r->new_pixel)
+         != (horflag ? r->pixel_width : r->pixel_height)))
     return Qnil;
 
   block_input ();
   window_resize_apply (r, horflag);
 
-  windows_or_buffers_changed++;
+  windows_or_buffers_changed = 30;
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
-  adjust_glyphs (f);
+  adjust_frame_glyphs (f);
   unblock_input ();
 
-  run_window_configuration_change_hook (f);
+  return Qt;
+}
+
+
+DEFUN ("window-resize-apply-total", Fwindow_resize_apply_total, Swindow_resize_apply_total, 0, 2, 0,
+       doc: /* Apply requested total size values for window-tree of FRAME.
+If FRAME is omitted or nil, it defaults to the selected frame.
+
+This function does not assign pixel or normal size values.  You should
+have run `window-resize-apply' before running this.
+
+Optional argument HORIZONTAL omitted or nil means apply requested
+height values.  HORIZONTAL non-nil means apply requested width
+values.  */)
+     (Lisp_Object frame, Lisp_Object horizontal)
+{
+  struct frame *f = decode_live_frame (frame);
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+
+  block_input ();
+  /* Necessary when deleting the top-/or leftmost window.  */
+  r->left_col = 0;
+  r->top_line = FRAME_TOP_MARGIN (f);
+  window_resize_apply_total (r, !NILP (horizontal));
+  unblock_input ();
 
   return Qt;
 }
@@ -3706,60 +4004,107 @@ be applied on the Elisp level.  */)
 
 /* Resize frame F's windows when number of lines of F is set to SIZE.
    HORFLAG 1 means resize windows when number of columns of F is set to
-   SIZE.
+   SIZE.  PIXELWISE 1 means to interpret SIZE as pixels.
 
    This function can delete all windows but the selected one in order to
    satisfy the request.  The result will be meaningful if and only if
    F's windows have meaningful sizes when you call this.  */
 void
-resize_frame_windows (struct frame *f, int size, bool horflag)
+resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
 {
   Lisp_Object root = f->root_window;
   struct window *r = XWINDOW (root);
   Lisp_Object mini = f->minibuffer_window;
   struct window *m;
+  /* old_size is the old size of the frame's root window.  */
+  int old_size = horflag ? r->total_cols : r->total_lines;
+  int old_pixel_size = horflag ? r->pixel_width : r->pixel_height;
   /* new_size is the new size of the frame's root window.  */
-  int new_size = (horflag
-                 ? size
-                 : (size
-                    - FRAME_TOP_MARGIN (f)
-                    - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
-                       ? 1 : 0)));
-
-  wset_top_line (r, make_number (FRAME_TOP_MARGIN (f)));
-  if (NILP (r->vchild) && NILP (r->hchild))
+  int new_size, new_pixel_size;
+
+  if (pixelwise)
+    {
+      new_pixel_size
+       = (horflag
+          ? size
+          : (size
+             - FRAME_TOP_MARGIN_HEIGHT (f)
+             - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+                ? FRAME_LINE_HEIGHT (f) : 0)));
+      new_size = new_pixel_size / (horflag
+                                  ? FRAME_COLUMN_WIDTH (f)
+                                  : FRAME_LINE_HEIGHT (f));
+    }
+  else
+    {
+      new_size= (horflag
+                ? size
+                : (size
+                   - FRAME_TOP_MARGIN (f)
+                   - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+                      ? 1 : 0)));
+      new_pixel_size = new_size * (horflag
+                                  ? FRAME_COLUMN_WIDTH (f)
+                                  : FRAME_LINE_HEIGHT (f));
+    }
+
+  r->top_line = FRAME_TOP_MARGIN (f);
+  r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
+
+  if (new_pixel_size == old_pixel_size)
+    return;
+  else if (WINDOW_LEAF_P (r))
     /* For a leaf root window just set the size.  */
     if (horflag)
-      wset_total_cols (r, make_number (new_size));
+      {
+       r->total_cols = new_size;
+       r->pixel_width = new_pixel_size;
+      }
     else
-      wset_total_lines (r, make_number (new_size));
+      {
+       r->total_lines = new_size;
+       r->pixel_height = new_pixel_size;
+      }
   else
     {
-      /* old_size is the old size of the frame's root window.  */
-      int old_size = XFASTINT (horflag ? r->total_cols
-                              : r->total_lines);
       Lisp_Object delta;
 
-      XSETINT (delta, new_size - old_size);
+      if (pixelwise)
+       XSETINT (delta, new_pixel_size - old_pixel_size);
+      else
+       XSETINT (delta, new_size - old_size);
+
       /* Try a "normal" resize first.  */
-      resize_root_window (root, delta, horflag ? Qt : Qnil, Qnil);
+      resize_root_window (root, delta, horflag ? Qt : Qnil, Qnil,
+                         pixelwise ? Qt : Qnil);
       if (window_resize_check (r, horflag)
-         && new_size == XINT (r->new_total))
-       window_resize_apply (r, horflag);
+         && new_pixel_size == XINT (r->new_pixel))
+       {
+         window_resize_apply (r, horflag);
+         window_pixel_to_total (r->frame, horflag ? Qt : Qnil);
+       }
       else
        {
          /* Try with "reasonable" minimum sizes next.  */
-         resize_root_window (root, delta, horflag ? Qt : Qnil, Qt);
+         resize_root_window (root, delta, horflag ? Qt : Qnil, Qt,
+                             pixelwise ? Qt : Qnil);
          if (window_resize_check (r, horflag)
-             && new_size == XINT (r->new_total))
-           window_resize_apply (r, horflag);
+             && new_pixel_size == XINT (r->new_pixel))
+           {
+             window_resize_apply (r, horflag);
+             window_pixel_to_total (r->frame, horflag ? Qt : Qnil);
+           }
          else
            {
              /* Finally, try with "safe" minimum sizes.  */
-             resize_root_window (root, delta, horflag ? Qt : Qnil, Qsafe);
+             resize_root_window (root, delta, horflag ? Qt : Qnil, Qsafe,
+                                 pixelwise ? Qt : Qnil);
              if (window_resize_check (r, horflag)
-                 && new_size == XINT (r->new_total))
-               window_resize_apply (r, horflag);
+                 && new_pixel_size == XINT (r->new_pixel))
+               {
+                 window_resize_apply (r, horflag);
+                 window_pixel_to_total (r->frame, horflag ? Qt : Qnil);
+               }
              else
                {
                  /* We lost.  Delete all windows but the frame's
@@ -3767,9 +4112,15 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
                  root = f->selected_window;
                  Fdelete_other_windows_internal (root, Qnil);
                  if (horflag)
-                   wset_total_cols (XWINDOW (root), make_number (new_size));
+                   {
+                     XWINDOW (root)->total_cols = new_size;
+                     XWINDOW (root)->pixel_width = new_pixel_size;
+                   }
                  else
-                   wset_total_lines (XWINDOW (root), make_number (new_size));
+                   {
+                     XWINDOW (root)->total_lines = new_size;
+                     XWINDOW (root)->pixel_height = new_pixel_size;
+                   }
                }
            }
        }
@@ -3779,43 +4130,47 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
     {
       m = XWINDOW (mini);
       if (horflag)
-       wset_total_cols (m, make_number (size));
+       {
+         m->total_cols = size;
+         m->pixel_width = new_pixel_size;
+       }
       else
        {
          /* Are we sure we always want 1 line here?  */
-         wset_total_lines (m, make_number (1));
-         wset_top_line
-           (m, make_number (XINT (r->top_line) + XINT (r->total_lines)));
+         m->total_lines = 1;
+         m->pixel_height = FRAME_LINE_HEIGHT (f);
+         m->top_line = r->top_line + r->total_lines;
+         m->pixel_top = r->pixel_top + r->pixel_height;
        }
     }
 
-  windows_or_buffers_changed++;
+  windows_or_buffers_changed = 31;
 }
 
 
 DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0,
        doc: /* Split window OLD.
-Second argument TOTAL-SIZE specifies the number of lines or columns of the
+Second argument PIXEL-SIZE specifies the number of pixels of the
 new window.  In any case TOTAL-SIZE must be a positive integer.
 
 Third argument SIDE nil (or `below') specifies that the new window shall
 be located below WINDOW.  SIDE `above' means the new window shall be
-located above WINDOW.  In both cases TOTAL-SIZE specifies the number of
-lines of the new window including space reserved for the mode and/or
+located above WINDOW.  In both cases PIXEL-SIZE specifies the pixel
+height of the new window including space reserved for the mode and/or
 header line.
 
 SIDE t (or `right') specifies that the new window shall be located on
 the right side of WINDOW.  SIDE `left' means the new window shall be
-located on the left of WINDOW.  In both cases TOTAL-SIZE specifies the
-number of columns of the new window including space reserved for fringes
-and the scrollbar or a divider column.
+located on the left of WINDOW.  In both cases PIXEL-SIZE specifies the
+width of the new window including space reserved for fringes and the
+scrollbar or a divider column.
 
 Fourth argument NORMAL-SIZE specifies the normal size of the new window
 according to the SIDE argument.
 
-The new total and normal sizes of all involved windows must have been
+The new pixel and normal sizes of all involved windows must have been
 set correctly.  See the code of `split-window' for how this is done.  */)
-  (Lisp_Object old, Lisp_Object total_size, Lisp_Object side, Lisp_Object normal_size)
+  (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size)
 {
   /* OLD (*o) is the window we have to split.  (*p) is either OLD's
      parent window or an internal window we have to install as OLD's new
@@ -3824,19 +4179,24 @@ set correctly.  See the code of `split-window' for how this is done.  */)
      NEW (*n) is the new window created with some parameters taken from
      REFERENCE (*r).  */
   register Lisp_Object new, frame, reference;
-  register struct window *o, *p, *n, *r;
+  register struct window *o, *p, *n, *r, *c;
   struct frame *f;
   bool horflag
     /* HORFLAG is 1 when we split side-by-side, 0 otherwise.  */
     = EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright);
-  int combination_limit = 0;
+  int combination_limit = 0, sum = 0;
+  int total_size;
 
   CHECK_WINDOW (old);
   o = XWINDOW (old);
   frame = WINDOW_FRAME (o);
   f = XFRAME (frame);
 
-  CHECK_NUMBER (total_size);
+  CHECK_NUMBER (pixel_size);
+  total_size
+    = XINT (pixel_size) / (horflag
+                          ? FRAME_COLUMN_WIDTH (f)
+                          : FRAME_LINE_HEIGHT (f));
 
   /* Set combination_limit to 1 if we have to make a new parent window.
      We do that if either `window-combination-limit' is t, or OLD has no
@@ -3844,9 +4204,9 @@ set correctly.  See the code of `split-window' for how this is done.  */)
   combination_limit =
     EQ (Vwindow_combination_limit, Qt)
     || NILP (o->parent)
-    || NILP (horflag
-            ? (XWINDOW (o->parent)->hchild)
-            : (XWINDOW (o->parent)->vchild));
+    || (horflag
+       ? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent))
+       : WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent)));
 
   /* We need a live reference window to initialize some parameters.  */
   if (WINDOW_LIVE_P (old))
@@ -3860,7 +4220,7 @@ set correctly.  See the code of `split-window' for how this is done.  */)
   /* The following bugs are caught by `split-window'.  */
   if (MINI_WINDOW_P (o))
     error ("Attempt to split minibuffer window");
-  else if (XINT (total_size) < (horflag ? 2 : 1))
+  else if (total_size < (horflag ? 2 : 1))
     error ("Size of new window too small (after split)");
   else if (!combination_limit && !NILP (Vwindow_combination_resize))
     /* `window-combination-resize' non-nil means try to resize OLD's siblings
@@ -3868,21 +4228,21 @@ set correctly.  See the code of `split-window' for how this is done.  */)
     {
       p = XWINDOW (o->parent);
       /* Temporarily pretend we split the parent window.  */
-      wset_new_total
-       (p, make_number (XINT (horflag ? p->total_cols : p->total_lines)
-                        - XINT (total_size)));
+      wset_new_pixel
+       (p, make_number ((horflag ? p->pixel_width : p->pixel_height)
+                        - XINT (pixel_size)));
       if (!window_resize_check (p, horflag))
        error ("Window sizes don't fit");
       else
        /* Undo the temporary pretension.  */
-       wset_new_total (p, horflag ? p->total_cols : p->total_lines);
+       wset_new_pixel (p, make_number (horflag ? p->pixel_width : p->pixel_height));
     }
   else
     {
       if (!window_resize_check (o, horflag))
        error ("Resizing old window failed");
-      else if (XINT (total_size) + XINT (o->new_total)
-              != XINT (horflag ? o->total_cols : o->total_lines))
+      else if (XINT (pixel_size) + XINT (o->new_pixel)
+              != (horflag ? o->pixel_width : o->pixel_height))
        error ("Sum of sizes of old and new window don't fit");
     }
 
@@ -3902,29 +4262,27 @@ set correctly.  See the code of `split-window' for how this is done.  */)
           that its children get merged into another window.  */
        wset_combination_limit (p, Qt);
       /* These get applied below.  */
-      wset_new_total (p, horflag ? o->total_cols : o->total_lines);
+      wset_new_pixel
+       (p, make_number (horflag ? o->pixel_width : o->pixel_height));
+      wset_new_total
+       (p, make_number (horflag ? o->total_cols : o->total_lines));
       wset_new_normal (p, new_normal);
     }
   else
     p = XWINDOW (o->parent);
 
-  windows_or_buffers_changed++;
+  windows_or_buffers_changed = 32;
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
   new = make_window ();
   n = XWINDOW (new);
   wset_frame (n, frame);
   wset_parent (n, o->parent);
-  wset_vchild (n, Qnil);
-  wset_hchild (n, Qnil);
 
   if (EQ (side, Qabove) || EQ (side, Qleft))
     {
       wset_prev (n, o->prev);
       if (NILP (n->prev))
-       if (horflag)
-         wset_hchild (p, new);
-       else
-         wset_vchild (p, new);
+       wset_combination (p, horflag, new);
       else
        wset_next (XWINDOW (n->prev), new);
       wset_next (n, old);
@@ -3940,40 +4298,55 @@ set correctly.  See the code of `split-window' for how this is done.  */)
     }
 
   n->window_end_valid = 0;
-  memset (&n->last_cursor, 0, sizeof n->last_cursor);
+  n->last_cursor_vpos = 0;
 
   /* Get special geometry settings from reference window.  */
-  wset_left_margin_cols (n, r->left_margin_cols);
-  wset_right_margin_cols (n, r->right_margin_cols);
-  wset_left_fringe_width (n, r->left_fringe_width);
-  wset_right_fringe_width (n, r->right_fringe_width);
+  n->left_margin_cols = r->left_margin_cols;
+  n->right_margin_cols = r->right_margin_cols;
+  n->left_fringe_width = r->left_fringe_width;
+  n->right_fringe_width = r->right_fringe_width;
   n->fringes_outside_margins = r->fringes_outside_margins;
-  wset_scroll_bar_width (n, r->scroll_bar_width);
+  n->scroll_bar_width = r->scroll_bar_width;
   wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
 
   /* Directly assign orthogonal coordinates and sizes.  */
   if (horflag)
     {
-      wset_top_line (n, o->top_line);
-      wset_total_lines (n, o->total_lines);
+      n->pixel_top = o->pixel_top;
+      n->top_line = o->top_line;
+      n->pixel_height = o->pixel_height;
+      n->total_lines = o->total_lines;
     }
   else
     {
-      wset_left_col (n, o->left_col);
-      wset_total_cols (n, o->total_cols);
+      n->pixel_left = o->pixel_left;
+      n->left_col = o->left_col;
+      n->pixel_width = o->pixel_width;
+      n->total_cols = o->total_cols;
     }
 
   /* Iso-coordinates and sizes are assigned by window_resize_apply,
      get them ready here.  */
-  wset_new_total (n, total_size);
+  wset_new_pixel (n, pixel_size);
+  c = XWINDOW (p->contents);
+  while (c)
+    {
+      if (c != n)
+       sum = sum + XINT (c->new_total);
+      c = NILP (c->next) ? 0 : XWINDOW (c->next);
+    }
+  wset_new_total (n, make_number ((horflag
+                                  ? p->total_cols
+                                  : p->total_lines)
+                                 - sum));
   wset_new_normal (n, normal_size);
 
   block_input ();
   window_resize_apply (p, horflag);
-  adjust_glyphs (f);
+  adjust_frame_glyphs (f);
   /* Set buffer of NEW to buffer of reference window.  Don't run
      any hooks.  */
-  set_window_buffer (new, r->buffer, 0, 1);
+  set_window_buffer (new, r->contents, 0, 1);
   unblock_input ();
 
   /* Maybe we should run the scroll functions in Elisp (which already
@@ -3995,13 +4368,11 @@ Signal an error when WINDOW is the only window on its frame.  */)
   register Lisp_Object parent, sibling, frame, root;
   struct window *w, *p, *s, *r;
   struct frame *f;
-  bool horflag;
-  int before_sibling = 0;
+  bool horflag, before_sibling = 0;
 
   w = decode_any_window (window);
   XSETWINDOW (window, w);
-  if (NILP (w->buffer)
-      && NILP (w->hchild) && NILP (w->vchild))
+  if (NILP (w->contents))
     /* It's a no-op to delete an already deleted window.  */
     return Qnil;
 
@@ -4015,7 +4386,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
     error ("Attempt to delete sole window of parent");
 
   p = XWINDOW (parent);
-  horflag = NILP (p->vchild);
+  horflag = WINDOW_HORIZONTAL_COMBINATION_P (p);
 
   frame = WINDOW_FRAME (w);
   f = XFRAME (frame);
@@ -4033,10 +4404,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
       sibling = w->next;
       s = XWINDOW (sibling);
       wset_prev (s, Qnil);
-      if (horflag)
-       wset_hchild (p, sibling);
-      else
-       wset_vchild (p, sibling);
+      wset_combination (p, horflag, sibling);
     }
   else
     /* Get SIBLING above (on the left of) WINDOW.  */
@@ -4049,15 +4417,14 @@ Signal an error when WINDOW is the only window on its frame.  */)
     }
 
   if (window_resize_check (r, horflag)
-      && EQ (r->new_total,
-            (horflag ? r->total_cols : r->total_lines)))
+      && (XINT (r->new_pixel)
+         == (horflag ? r->pixel_width : r->pixel_height)))
     /* We can delete WINDOW now.  */
     {
 
       /* Block input.  */
       block_input ();
       window_resize_apply (p, horflag);
-
       /* If this window is referred to by the dpyinfo's mouse
         highlight, invalidate that slot to be safe (Bug#9904).  */
       if (!FRAME_INITIAL_P (f))
@@ -4068,24 +4435,19 @@ Signal an error when WINDOW is the only window on its frame.  */)
            hlinfo->mouse_face_window = Qnil;
        }
 
-      windows_or_buffers_changed++;
+      windows_or_buffers_changed = 33;
       Vwindow_list = Qnil;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
       wset_next (w, Qnil);  /* Don't delete w->next too.  */
       free_window_matrices (w);
 
-      if (!NILP (w->vchild))
+      if (WINDOWP (w->contents))
        {
-         delete_all_child_windows (w->vchild);
-         wset_vchild (w, Qnil);
+         delete_all_child_windows (w->contents);
+         wset_combination (w, 0, Qnil);
        }
-      else if (!NILP (w->hchild))
-       {
-         delete_all_child_windows (w->hchild);
-         wset_hchild (w, Qnil);
-       }
-      else if (!NILP (w->buffer))
+      else
        {
          unshow_buffer (w);
          unchain_marker (XMARKER (w->pointm));
@@ -4104,13 +4466,12 @@ Signal an error when WINDOW is the only window on its frame.  */)
          wset_normal_cols (s, p->normal_cols);
          wset_normal_lines (s, p->normal_lines);
          /* Mark PARENT as deleted.  */
-         wset_vchild (p, Qnil);
-         wset_hchild (p, Qnil);
+         wset_combination (p, 0, Qnil);
          /* Try to merge SIBLING into its new parent.  */
          recombine_windows (sibling);
        }
 
-      adjust_glyphs (f);
+      adjust_frame_glyphs (f);
 
       if (!WINDOW_LIVE_P (FRAME_SELECTED_WINDOW (f)))
        /* We deleted the frame's selected window.  */
@@ -4153,10 +4514,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
       if (before_sibling)
        {
          wset_prev (s, window);
-         if (horflag)
-           wset_hchild (p, window);
-         else
-           wset_vchild (p, window);
+         wset_combination (p, horflag, window);
        }
       else
        {
@@ -4177,72 +4535,89 @@ Signal an error when WINDOW is the only window on its frame.  */)
 /* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we
    can.  */
 void
-grow_mini_window (struct window *w, int delta)
+grow_mini_window (struct window *w, int delta, bool pixelwise)
 {
   struct frame *f = XFRAME (w->frame);
   struct window *r;
-  Lisp_Object root, value;
+  Lisp_Object root, height;
+  int line_height, pixel_height;
 
   eassert (MINI_WINDOW_P (w));
   eassert (delta >= 0);
 
-  root = FRAME_ROOT_WINDOW (f);
-  r = XWINDOW (root);
-  value = call2 (Qwindow_resize_root_window_vertically,
-                root, make_number (- delta));
-  if (INTEGERP (value) && window_resize_check (r, 0))
+  if (delta > 0)
     {
-      block_input ();
-      window_resize_apply (r, 0);
+      root = FRAME_ROOT_WINDOW (f);
+      r = XWINDOW (root);
+      height = call3 (Qwindow_resize_root_window_vertically,
+                     root, make_number (- delta), pixelwise ? Qt : Qnil);
+      if (INTEGERP (height) && window_resize_check (r, 0))
+       {
+         block_input ();
+         window_resize_apply (r, 0);
 
-      /* Grow the mini-window.  */
-      wset_top_line
-       (w, make_number (XFASTINT (r->top_line) + XFASTINT (r->total_lines)));
-      wset_total_lines
-       (w, make_number (XFASTINT (w->total_lines) - XINT (value)));
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
+         if (pixelwise)
+           {
+             pixel_height = min (-XINT (height), INT_MAX - w->pixel_height);
+             line_height = pixel_height / FRAME_LINE_HEIGHT (f);
+           }
+         else
+           {
+             line_height = min (-XINT (height),
+                                ((INT_MAX - w->pixel_height)
+                                 / FRAME_LINE_HEIGHT (f)));
+             pixel_height = line_height * FRAME_LINE_HEIGHT (f);
+           }
 
-      windows_or_buffers_changed++;
-      adjust_glyphs (f);
-      unblock_input ();
+         /* Grow the mini-window.  */
+         w->pixel_top = r->pixel_top + r->pixel_height;
+         w->top_line = r->top_line + r->total_lines;
+         w->pixel_height += pixel_height;
+         w->total_lines += line_height;
+
+         /* Enforce full redisplay of the frame.  */
+         /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
+         fset_redisplay (f);
+         adjust_frame_glyphs (f);
+         unblock_input ();
+       }
     }
 }
 
-
-/* Shrink mini-window W.  */
+/* Shrink mini-window W to one line.  */
 void
-shrink_mini_window (struct window *w)
+shrink_mini_window (struct window *w, bool pixelwise)
 {
   struct frame *f = XFRAME (w->frame);
   struct window *r;
-  Lisp_Object root, value;
-  EMACS_INT size;
+  Lisp_Object root, delta;
+  EMACS_INT height, unit;
 
   eassert (MINI_WINDOW_P (w));
 
-  size = XINT (w->total_lines);
-  if (size > 1)
+  height = pixelwise ? w->pixel_height : w->total_lines;
+  unit = pixelwise ? FRAME_LINE_HEIGHT (f) : 1;
+  if (height > unit)
     {
       root = FRAME_ROOT_WINDOW (f);
       r = XWINDOW (root);
-      value = call2 (Qwindow_resize_root_window_vertically,
-                    root, make_number (size - 1));
-      if (INTEGERP (value) && window_resize_check (r, 0))
+      delta = call3 (Qwindow_resize_root_window_vertically,
+                    root, make_number (height - unit),
+                    pixelwise ? Qt : Qnil);
+      if (INTEGERP (delta) && window_resize_check (r, 0))
        {
          block_input ();
          window_resize_apply (r, 0);
 
          /* Shrink the mini-window.  */
-         wset_top_line (w, make_number (XFASTINT (r->top_line)
-                                        + XFASTINT (r->total_lines)));
-         wset_total_lines (w, make_number (1));
-
-         w->last_modified = 0;
-         w->last_overlay_modified = 0;
-
-         windows_or_buffers_changed++;
-         adjust_glyphs (f);
+         w->top_line = r->top_line + r->total_lines;
+         w->total_lines = 1;
+         w->pixel_top = r->pixel_top + r->pixel_height;
+         w->pixel_height = FRAME_LINE_HEIGHT (f);
+         /* Enforce full redisplay of the frame.  */
+         /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
+         fset_redisplay (f);
+         adjust_frame_glyphs (f);
          unblock_input ();
        }
       /* If the above failed for whatever strange reason we must make a
@@ -4270,27 +4645,27 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
     error ("Cannot resize a minibuffer-only frame");
 
   r = XWINDOW (FRAME_ROOT_WINDOW (f));
-  height = XINT (r->total_lines) + XINT (w->total_lines);
+  height = r->pixel_height + w->pixel_height;
   if (window_resize_check (r, 0)
-      && XINT (w->new_total) > 0
-      && height == XINT (r->new_total) + XINT (w->new_total))
+      && XINT (w->new_pixel) > 0
+      && height == XINT (r->new_pixel) + XINT (w->new_pixel))
     {
       block_input ();
       window_resize_apply (r, 0);
 
-      wset_total_lines (w, w->new_total);
-      wset_top_line (w, make_number (XINT (r->top_line)
-                                    + XINT (r->total_lines)));
+      w->total_lines = XFASTINT (w->new_total);
+      w->top_line = r->top_line + r->total_lines;
+      w->pixel_height = XFASTINT (w->new_pixel);
+      w->pixel_top = r->pixel_top + r->pixel_height;
 
-      windows_or_buffers_changed++;
+      windows_or_buffers_changed = 36;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
-      adjust_glyphs (f);
+      adjust_frame_glyphs (f);
       unblock_input ();
-
-      run_window_configuration_change_hook (f);
       return Qt;
     }
-  else error ("Failed to resize minibuffer window");
+  else
+    error ("Failed to resize minibuffer window");
 }
 \f
 /* Mark window cursors off for all windows in the window tree rooted
@@ -4303,10 +4678,8 @@ mark_window_cursors_off (struct window *w)
 {
   while (w)
     {
-      if (!NILP (w->hchild))
-       mark_window_cursors_off (XWINDOW (w->hchild));
-      else if (!NILP (w->vchild))
-       mark_window_cursors_off (XWINDOW (w->vchild));
+      if (WINDOWP (w->contents))
+       mark_window_cursors_off (XWINDOW (w->contents));
       else
        w->phys_cursor_on_p = 0;
 
@@ -4320,13 +4693,12 @@ mark_window_cursors_off (struct window *w)
 int
 window_internal_height (struct window *w)
 {
-  int ht = XFASTINT (w->total_lines);
+  int ht = w->total_lines;
 
   if (!MINI_WINDOW_P (w))
     {
       if (!NILP (w->parent)
-         || !NILP (w->vchild)
-         || !NILP (w->hchild)
+         || WINDOWP (w->contents)
          || !NILP (w->next)
          || !NILP (w->prev)
          || WINDOW_WANTS_MODELINE_P (w))
@@ -4351,7 +4723,7 @@ window_internal_height (struct window *w)
    respectively.  */
 
 static void
-window_scroll (Lisp_Object window, EMACS_INT n, int whole, int noerror)
+window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror)
 {
   immediate_quit = 1;
   n = clip_to_bounds (INT_MIN, n, INT_MAX);
@@ -4363,6 +4735,8 @@ window_scroll (Lisp_Object window, EMACS_INT n, int whole, int noerror)
   else
     window_scroll_line_based (window, n, whole, noerror);
 
+  /* Bug#15957.  */
+  XWINDOW (window)->window_end_valid = 0;
   immediate_quit = 0;
 }
 
@@ -4372,7 +4746,7 @@ window_scroll (Lisp_Object window, EMACS_INT n, int whole, int noerror)
    descriptions.  */
 
 static void
-window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
+window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
 {
   struct it it;
   struct window *w = XWINDOW (window);
@@ -4382,6 +4756,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
   int vscrolled = 0;
   int x, y, rtop, rbot, rowh, vpos;
   void *itdata = NULL;
+  int window_total_lines;
+  int frame_line_height = default_line_pixel_height (w);
 
   SET_TEXT_POS_FROM_MARKER (start, w->start);
   /* Scrolling a minibuffer window via scroll bar when the echo area
@@ -4425,7 +4801,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
       if (rtop || rbot)                /* partially visible */
        {
          int px;
-         int dy = WINDOW_FRAME_LINE_HEIGHT (w);
+         int dy = frame_line_height;
          if (whole)
            dy = max ((window_box_height (w)
                       - next_screen_context_lines * dy),
@@ -4465,11 +4841,9 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
                  else
                    spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV);
                  set_marker_restricted (w->start, make_number (spos),
-                                        w->buffer);
+                                        w->contents);
                  w->start_at_line_beg = 1;
                  w->update_mode_line = 1;
-                 w->last_modified = 0;
-                 w->last_overlay_modified = 0;
                  /* Set force_start so that redisplay_window will run the
                     window-scroll-functions.  */
                  w->force_start = 1;
@@ -4511,7 +4885,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
   if (whole)
     {
       ptrdiff_t start_pos = IT_CHARPOS (it);
-      int dy = WINDOW_FRAME_LINE_HEIGHT (w);
+      int dy = frame_line_height;
       dy = max ((window_box_height (w)
                 - next_screen_context_lines * dy),
                dy) * n;
@@ -4558,7 +4932,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
                 visible.  */
              w->vscroll = (it.last_visible_y
                            - it.current_y + it.max_ascent + it.max_descent);
-             adjust_glyphs (it.f);
+             adjust_frame_glyphs (it.f);
            }
          else
            {
@@ -4589,7 +4963,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
 
       /* If control gets here, then we vscrolled.  */
 
-      XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+      XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1;
 
       /* Don't try to change the window start below.  */
       vscrolled = 1;
@@ -4609,13 +4983,11 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
        }
 
       /* Set the window start, and set up the window for redisplay.  */
-      set_marker_restricted_both (w->start, w->buffer, IT_CHARPOS (it),
+      set_marker_restricted_both (w->start, w->contents, IT_CHARPOS (it),
                                  IT_BYTEPOS (it));
       bytepos = marker_byte_position (w->start);
       w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n');
       w->update_mode_line = 1;
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
       /* Set force_start so that redisplay_window will run the
         window-scroll-functions.  */
       w->force_start = 1;
@@ -4628,10 +5000,12 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
   /* Move PT out of scroll margins.
      This code wants current_y to be zero at the window start position
      even if there is a header line.  */
+  window_total_lines
+    = w->total_lines * WINDOW_FRAME_LINE_HEIGHT (w) / frame_line_height;
   this_scroll_margin = max (0, scroll_margin);
   this_scroll_margin
-    = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
-  this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+    = min (this_scroll_margin, window_total_lines / 4);
+  this_scroll_margin *= frame_line_height;
 
   if (n > 0)
     {
@@ -4736,7 +5110,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
    See the comment of window_scroll for parameter descriptions.  */
 
 static void
-window_scroll_line_based (Lisp_Object window, int n, int whole, int noerror)
+window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror)
 {
   register struct window *w = XWINDOW (window);
   /* Fvertical_motion enters redisplay, which can trigger
@@ -4748,7 +5122,7 @@ window_scroll_line_based (Lisp_Object window, int n, int whole, int noerror)
   register ptrdiff_t pos, pos_byte;
   register int ht = window_internal_height (w);
   register Lisp_Object tem;
-  int lose;
+  bool lose;
   Lisp_Object bolp;
   ptrdiff_t startpos = marker_position (w->start);
   ptrdiff_t startbyte = marker_byte_position (w->start);
@@ -4807,13 +5181,11 @@ window_scroll_line_based (Lisp_Object window, int n, int whole, int noerror)
     {
       /* Don't use a scroll margin that is negative or too large.  */
       int this_scroll_margin =
-       max (0, min (scroll_margin, XINT (w->total_lines) / 4));
+       max (0, min (scroll_margin, w->total_lines / 4));
 
-      set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
+      set_marker_restricted_both (w->start, w->contents, pos, pos_byte);
       w->start_at_line_beg = !NILP (bolp);
       w->update_mode_line = 1;
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
       /* Set force_start so that redisplay_window will run
         the window-scroll-functions.  */
       w->force_start = 1;
@@ -4903,13 +5275,13 @@ scroll_command (Lisp_Object n, int direction)
 
   /* If selected window's buffer isn't current, make it current for
      the moment.  But don't screw up if window_scroll gets an error.  */
-  if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+  if (XBUFFER (XWINDOW (selected_window)->contents) != current_buffer)
     {
       record_unwind_protect (save_excursion_restore, save_excursion_save ());
-      Fset_buffer (XWINDOW (selected_window)->buffer);
+      Fset_buffer (XWINDOW (selected_window)->contents);
 
       /* Make redisplay consider other windows than just selected_window.  */
-      ++windows_or_buffers_changed;
+      windows_or_buffers_changed = 37;
     }
 
   if (NILP (n))
@@ -5019,9 +5391,9 @@ specifies the window to scroll.  This takes precedence over
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
-  ++windows_or_buffers_changed;
+  windows_or_buffers_changed = 38;
 
-  Fset_buffer (w->buffer);
+  Fset_buffer (w->contents);
   SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm));
 
   if (NILP (arg))
@@ -5055,7 +5427,7 @@ by this function.  This happens in an interactive call.  */)
 {
   struct window *w = XWINDOW (selected_window);
   EMACS_INT requested_arg = (NILP (arg)
-                            ? window_body_cols (w) - 2
+                            ? window_body_width (w, 0) - 2
                             : XINT (Fprefix_numeric_value (arg)));
   Lisp_Object result = set_window_hscroll (w, w->hscroll + requested_arg);
 
@@ -5078,7 +5450,7 @@ by this function.  This happens in an interactive call.  */)
 {
   struct window *w = XWINDOW (selected_window);
   EMACS_INT requested_arg = (NILP (arg)
-                            ? window_body_cols (w) - 2
+                            ? window_body_width (w, 0) - 2
                             : XINT (Fprefix_numeric_value (arg)));
   Lisp_Object result = set_window_hscroll (w, w->hscroll - requested_arg);
 
@@ -5109,16 +5481,15 @@ displayed_window_lines (struct window *w)
 {
   struct it it;
   struct text_pos start;
-  ptrdiff_t charpos = marker_position (w->start);
   int height = window_box_height (w);
   struct buffer *old_buffer;
   int bottom_y;
   void *itdata = NULL;
 
-  if (XBUFFER (w->buffer) != current_buffer)
+  if (XBUFFER (w->contents) != current_buffer)
     {
       old_buffer = current_buffer;
-      set_buffer_internal (XBUFFER (w->buffer));
+      set_buffer_internal (XBUFFER (w->contents));
     }
   else
     old_buffer = NULL;
@@ -5126,12 +5497,7 @@ displayed_window_lines (struct window *w)
   /* In case W->start is out of the accessible range, do something
      reasonable.  This happens in Info mode when Info-scroll-down
      calls (recenter -1) while W->start is 1.  */
-  if (charpos < BEGV)
-    SET_TEXT_POS (start, BEGV, BEGV_BYTE);
-  else if (charpos > ZV)
-    SET_TEXT_POS (start, ZV, ZV_BYTE);
-  else
-    SET_TEXT_POS_FROM_MARKER (start, w->start);
+  CLIP_TEXT_POS_FROM_MARKER (start, w->start);
 
   itdata = bidi_shelve_cache ();
   start_display (&it, w, start);
@@ -5180,9 +5546,9 @@ and redisplay normally--don't erase and redraw the frame.  */)
   (register Lisp_Object arg)
 {
   struct window *w = XWINDOW (selected_window);
-  struct buffer *buf = XBUFFER (w->buffer);
+  struct buffer *buf = XBUFFER (w->contents);
   struct buffer *obuf = current_buffer;
-  int center_p = 0;
+  bool center_p = 0;
   ptrdiff_t charpos, bytepos;
   EMACS_INT iarg IF_LINT (= 0);
   int this_scroll_margin;
@@ -5201,9 +5567,9 @@ and redisplay normally--don't erase and redraw the frame.  */)
          /* Invalidate pixel data calculated for all compositions.  */
          for (i = 0; i < n_compositions; i++)
            composition_table[i]->font = NULL;
-
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
          WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
-
+#endif
          Fredraw_frame (WINDOW_FRAME (w));
          SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
        }
@@ -5224,7 +5590,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
   /* Do this after making BUF current
      in case scroll_margin is buffer-local.  */
   this_scroll_margin =
-    max (0, min (scroll_margin, XFASTINT (w->total_lines) / 4));
+    max (0, min (scroll_margin, w->total_lines / 4));
 
   /* Handle centering on a graphical frame specially.  Such frames can
      have variable-height lines and centering point on the basis of
@@ -5346,7 +5712,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
     }
 
   /* Set the new window start.  */
-  set_marker_both (w->start, w->buffer, charpos, bytepos);
+  set_marker_both (w->start, w->contents, charpos, bytepos);
   w->window_end_valid = 0;
 
   w->optional_new_start = 1;
@@ -5358,22 +5724,36 @@ and redisplay normally--don't erase and redraw the frame.  */)
   return Qnil;
 }
 
-DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
+DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width,
        0, 1, 0,
-       doc: /* Return the height in lines of the text display area of WINDOW.
+       doc: /* Return the width in columns of the text display area of WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
-The returned height does not include the mode line, any header line,
-nor any partial-height lines at the bottom of the text area.  */)
+The returned width does not include dividers, scrollbars, margins,
+fringes, nor any partial-width columns at the right of the text
+area.  */)
   (Lisp_Object window)
 {
   struct window *w = decode_live_window (window);
-  int pixel_height = window_box_height (w);
-  int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
-  return make_number (line_height);
+
+  return make_number (window_box_width (w, TEXT_AREA)
+                     / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)));
 }
 
+DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
+       0, 1, 0,
+       doc: /* Return the height in lines of the text display area of WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The returned height does not include dividers, the mode line, any header
+line, nor any partial-height lines at the bottom of the text area.  */)
+  (Lisp_Object window)
+{
+  struct window *w = decode_live_window (window);
 
+  return make_number (window_box_height (w)
+                     / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)));
+}
 \f
 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
        1, 1, "P",
@@ -5390,9 +5770,8 @@ zero means top of window, negative means relative to bottom of window.  */)
   int this_scroll_margin;
 #endif
 
-  if (!(BUFFERP (w->buffer)
-       && XBUFFER (w->buffer) == current_buffer))
-    /* This test is needed to make sure PT/PT_BYTE make sense in w->buffer
+  if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer))
+    /* This test is needed to make sure PT/PT_BYTE make sense in w->contents
        when passed below to set_marker_both.  */
     error ("move-to-window-line called from unrelated buffer");
 
@@ -5402,7 +5781,7 @@ zero means top of window, negative means relative to bottom of window.  */)
     {
       int height = window_internal_height (w);
       Fvertical_motion (make_number (- (height / 2)), window);
-      set_marker_both (w->start, w->buffer, PT, PT_BYTE);
+      set_marker_both (w->start, w->contents, PT, PT_BYTE);
       w->start_at_line_beg = !NILP (Fbolp ());
       w->force_start = 1;
     }
@@ -5466,10 +5845,16 @@ struct save_window_data
     Lisp_Object saved_windows;
 
     /* All fields above are traced by the GC.
-       From `fame-cols' down, the fields are ignored by the GC.  */
-
-    int frame_cols, frame_lines, frame_menu_bar_lines;
-    int frame_tool_bar_lines;
+       From `frame-cols' down, the fields are ignored by the GC.  */
+    /* We should be able to do without the following two.  */
+    int frame_cols, frame_lines;
+    /* These two should get eventually replaced by their pixel
+       counterparts.  */
+    int frame_menu_bar_lines, frame_tool_bar_lines;
+    int frame_text_width, frame_text_height;
+    /* These are currently unused.  We need them as soon as we convert
+       to pixels.  */
+    int frame_menu_bar_height, frame_tool_bar_height;
   };
 
 /* This is saved as a Lisp_Vector  */
@@ -5478,6 +5863,7 @@ struct saved_window
   struct vectorlike_header header;
 
   Lisp_Object window, buffer, start, pointm, mark;
+  Lisp_Object pixel_left, pixel_top, pixel_height, pixel_width;
   Lisp_Object left_col, top_line, total_cols, total_lines;
   Lisp_Object normal_cols, normal_lines;
   Lisp_Object hscroll, min_hscroll;
@@ -5528,7 +5914,7 @@ the return value is nil.  Otherwise the value is t.  */)
   struct Lisp_Vector *saved_windows;
   Lisp_Object new_current_buffer;
   Lisp_Object frame;
-  FRAME_PTR f;
+  struct frame *f;
   ptrdiff_t old_point = -1;
 
   CHECK_WINDOW_CONFIGURATION (configuration);
@@ -5552,9 +5938,9 @@ the return value is nil.  Otherwise the value is t.  */)
           window-point of the final-selected-window to the window-point of
           the current-selected-window.  So we have to be careful which
           point of the current-buffer we copy into old_point.  */
-       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
+       if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer)
            && WINDOWP (selected_window)
-           && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
+           && EQ (XWINDOW (selected_window)->contents, new_current_buffer)
            && !EQ (selected_window, data->current_window))
          old_point = marker_position (XWINDOW (data->current_window)->pointm);
        else
@@ -5568,7 +5954,7 @@ the return value is nil.  Otherwise the value is t.  */)
           So if possible we want this arbitrary choice of "which point" to
           be the one from the to-be-selected-window so as to prevent this
           window's cursor from being copied from another window.  */
-       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
+       if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer)
            /* If current_window = selected_window, its point is in BUF_PT.  */
            && !EQ (selected_window, data->current_window))
          old_point = marker_position (XWINDOW (data->current_window)->pointm);
@@ -5598,8 +5984,12 @@ the return value is nil.  Otherwise the value is t.  */)
         made, we change the frame to the size specified in the
         configuration, restore the configuration, and then resize it
         back.  We keep track of the prevailing height in these variables.  */
-      int previous_frame_lines = FRAME_LINES (f);
-      int previous_frame_cols =  FRAME_COLS  (f);
+      int previous_frame_text_height = FRAME_TEXT_HEIGHT (f);
+      int previous_frame_text_width =  FRAME_TEXT_WIDTH  (f);
+      /* int previous_frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); */
+      /* int previous_frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f); */
+      /* int previous_frame_lines = FRAME_LINES (f); */
+      /* int previous_frame_cols =  FRAME_COLS  (f); */
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
       int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
 
@@ -5610,8 +6000,8 @@ the return value is nil.  Otherwise the value is t.  */)
          p = SAVED_WINDOW_N (saved_windows, k);
          window = p->window;
          w = XWINDOW (window);
-         if (!NILP (w->buffer)
-             && !EQ (w->buffer, p->buffer)
+         if (BUFFERP (w->contents)
+             && !EQ (w->contents, p->buffer)
              && BUFFER_LIVE_P (XBUFFER (p->buffer)))
            /* If a window we restore gets another buffer, record the
               window's old buffer.  */
@@ -5622,21 +6012,26 @@ the return value is nil.  Otherwise the value is t.  */)
         if it runs during this.  */
       block_input ();
 
-      if (data->frame_lines != previous_frame_lines
-         || data->frame_cols != previous_frame_cols)
-       change_frame_size (f, data->frame_lines,
-                          data->frame_cols, 0, 0, 0);
-#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
-      if (data->frame_menu_bar_lines
-         != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
-                             make_number (0));
+      if (data->frame_text_width != previous_frame_text_width
+         || data->frame_text_height != previous_frame_text_height)
+       change_frame_size (f, data->frame_text_width,
+                          data->frame_text_height, 0, 0, 0, 1);
+
+      if (data->frame_menu_bar_lines != previous_frame_menu_bar_lines)
+       {
 #ifdef HAVE_WINDOW_SYSTEM
-      if (data->frame_tool_bar_lines
-         != previous_frame_tool_bar_lines)
+         if (FRAME_WINDOW_P (f))
+           x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
+                                 make_number (0));
+         else  /* TTY or MSDOS */
+#endif
+           set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
+                               make_number (0));
+       }
+#ifdef HAVE_WINDOW_SYSTEM
+      if (data->frame_tool_bar_lines != previous_frame_tool_bar_lines)
        x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
                              make_number (0));
-#endif
 #endif
 
       /* "Swap out" point from the selected window's buffer
@@ -5644,16 +6039,16 @@ the return value is nil.  Otherwise the value is t.  */)
         window holds garbage.)  We do this now, before
         restoring the window contents, and prevent it from
         being done later on when we select a new window.  */
-      if (! NILP (XWINDOW (selected_window)->buffer))
+      if (! NILP (XWINDOW (selected_window)->contents))
        {
          w = XWINDOW (selected_window);
          set_marker_both (w->pointm,
-                          w->buffer,
-                          BUF_PT (XBUFFER (w->buffer)),
-                          BUF_PT_BYTE (XBUFFER (w->buffer)));
+                          w->contents,
+                          BUF_PT (XBUFFER (w->contents)),
+                          BUF_PT_BYTE (XBUFFER (w->contents)));
        }
 
-      windows_or_buffers_changed++;
+      windows_or_buffers_changed = 39;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
       /* Problem: Freeing all matrices and later allocating them again
@@ -5697,39 +6092,34 @@ the return value is nil.  Otherwise the value is t.  */)
            {
              wset_prev (w, Qnil);
              if (!NILP (w->parent))
-               {
-                 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
-                   {
-                     wset_vchild (XWINDOW (w->parent), p->window);
-                     wset_hchild (XWINDOW (w->parent), Qnil);
-                   }
-                 else
-                   {
-                     wset_hchild (XWINDOW (w->parent), p->window);
-                     wset_vchild (XWINDOW (w->parent), Qnil);
-                   }
-               }
+               wset_combination (XWINDOW (w->parent),
+                                 (XINT (p->total_cols)
+                                  != XWINDOW (w->parent)->total_cols),
+                                 p->window);
            }
 
-         /* If we squirreled away the buffer in the window's height,
-            restore it now.  */
-         if (BUFFERP (w->total_lines))
-           wset_buffer (w, w->total_lines);
-         wset_left_col (w, p->left_col);
-         wset_top_line (w, p->top_line);
-         wset_total_cols (w, p->total_cols);
-         wset_total_lines (w, p->total_lines);
+         /* If we squirreled away the buffer, restore it now.  */
+         if (BUFFERP (w->combination_limit))
+           wset_buffer (w, w->combination_limit);
+         w->pixel_left = XFASTINT (p->pixel_left);
+         w->pixel_top = XFASTINT (p->pixel_top);
+         w->pixel_width = XFASTINT (p->pixel_width);
+         w->pixel_height = XFASTINT (p->pixel_height);
+         w->left_col = XFASTINT (p->left_col);
+         w->top_line = XFASTINT (p->top_line);
+         w->total_cols = XFASTINT (p->total_cols);
+         w->total_lines = XFASTINT (p->total_lines);
          wset_normal_cols (w, p->normal_cols);
          wset_normal_lines (w, p->normal_lines);
          w->hscroll = XFASTINT (p->hscroll);
          w->min_hscroll = XFASTINT (p->min_hscroll);
          wset_display_table (w, p->display_table);
-         wset_left_margin_cols (w, p->left_margin_cols);
-         wset_right_margin_cols (w, p->right_margin_cols);
-         wset_left_fringe_width (w, p->left_fringe_width);
-         wset_right_fringe_width (w, p->right_fringe_width);
+         w->left_margin_cols = XINT (p->left_margin_cols);
+         w->right_margin_cols = XINT (p->right_margin_cols);
+         w->left_fringe_width = XINT (p->left_fringe_width);
+         w->right_fringe_width = XINT (p->right_fringe_width);
          w->fringes_outside_margins = !NILP (p->fringes_outside_margins);
-         wset_scroll_bar_width (w, p->scroll_bar_width);
+         w->scroll_bar_width = XINT (p->scroll_bar_width);
          wset_vertical_scroll_bar_type (w, p->vertical_scroll_bar_type);
          wset_dedicated (w, p->dedicated);
          wset_combination_limit (w, p->combination_limit);
@@ -5755,23 +6145,16 @@ the return value is nil.  Otherwise the value is t.  */)
                }
            }
 
-         w->last_modified = 0;
-         w->last_overlay_modified = 0;
-
-         /* Reinstall the saved buffer and pointers into it.  */
-         if (NILP (p->buffer))
-           /* An internal window.  */
-           wset_buffer (w, p->buffer);
-         else if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
+         if (BUFFERP (p->buffer) && BUFFER_LIVE_P (XBUFFER (p->buffer)))
            /* If saved buffer is alive, install it.  */
            {
              wset_buffer (w, p->buffer);
              w->start_at_line_beg = !NILP (p->start_at_line_beg);
-             set_marker_restricted (w->start, p->start, w->buffer);
+             set_marker_restricted (w->start, p->start, w->contents);
              set_marker_restricted (w->pointm, p->pointm,
-                                    w->buffer);
-             Fset_marker (BVAR (XBUFFER (w->buffer), mark),
-                          p->mark, w->buffer);
+                                    w->contents);
+             Fset_marker (BVAR (XBUFFER (w->contents), mark),
+                          p->mark, w->contents);
 
              /* As documented in Fcurrent_window_configuration, don't
                 restore the location of point in the buffer which was
@@ -5780,23 +6163,21 @@ the return value is nil.  Otherwise the value is t.  */)
                  && XBUFFER (p->buffer) == current_buffer)
                Fgoto_char (w->pointm);
             }
-          else if (!NILP (w->buffer)
-                   && BUFFER_LIVE_P (XBUFFER (w->buffer)))
-            /* Keep window's old buffer; make sure the markers are
-               real.  */
-            {
-              /* Set window markers at start of visible range.  */
-              if (XMARKER (w->start)->buffer == 0)
-                set_marker_restricted_both (w->start, w->buffer, 0, 0);
-              if (XMARKER (w->pointm)->buffer == 0)
-                set_marker_restricted_both
-                  (w->pointm, w->buffer,
-                   BUF_PT (XBUFFER (w->buffer)),
-                   BUF_PT_BYTE (XBUFFER (w->buffer)));
-              w->start_at_line_beg = 1;
-            }
-         else
-           /* Window has no live buffer, get one.  */
+         else if (BUFFERP (w->contents) && BUFFER_LIVE_P (XBUFFER (w->contents)))
+           /* Keep window's old buffer; make sure the markers are real.  */
+           {
+             /* Set window markers at start of visible range.  */
+             if (XMARKER (w->start)->buffer == 0)
+               set_marker_restricted_both (w->start, w->contents, 0, 0);
+             if (XMARKER (w->pointm)->buffer == 0)
+               set_marker_restricted_both
+                 (w->pointm, w->contents,
+                  BUF_PT (XBUFFER (w->contents)),
+                  BUF_PT_BYTE (XBUFFER (w->contents)));
+             w->start_at_line_beg = 1;
+           }
+         else if (!NILP (w->start))
+           /* Leaf window has no live buffer, get one.  */
            {
              /* Get the buffer via other_buffer_safely in order to
              avoid showing an unimportant buffer and, if necessary, to
@@ -5805,8 +6186,8 @@ the return value is nil.  Otherwise the value is t.  */)
              wset_buffer (w, other_buffer_safely (Fcurrent_buffer ()));
              /* This will set the markers to beginning of visible
                 range.  */
-             set_marker_restricted_both (w->start, w->buffer, 0, 0);
-             set_marker_restricted_both (w->pointm, w->buffer, 0, 0);
+             set_marker_restricted_both (w->start, w->contents, 0, 0);
+             set_marker_restricted_both (w->pointm, w->contents, 0, 0);
              w->start_at_line_beg = 1;
              if (!NILP (w->dedicated))
                /* Record this window as dead.  */
@@ -5819,55 +6200,50 @@ the return value is nil.  Otherwise the value is t.  */)
       fset_root_window (f, data->root_window);
       /* Arrange *not* to restore point in the buffer that was
         current when the window configuration was saved.  */
-      if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
+      if (EQ (XWINDOW (data->current_window)->contents, new_current_buffer))
        set_marker_restricted (XWINDOW (data->current_window)->pointm,
                               make_number (old_point),
-                              XWINDOW (data->current_window)->buffer);
-
-      /* In the following call to `select-window', prevent "swapping out
-        point" in the old selected window using the buffer that has
-        been restored into it.  We already swapped out that point from
-        that window's old buffer.  */
-      select_window (data->current_window, Qnil, 1);
-      BVAR (XBUFFER (XWINDOW (selected_window)->buffer), last_selected_window)
-       = selected_window;
+                              XWINDOW (data->current_window)->contents);
 
       if (NILP (data->focus_frame)
          || (FRAMEP (data->focus_frame)
              && FRAME_LIVE_P (XFRAME (data->focus_frame))))
        Fredirect_frame_focus (frame, data->focus_frame);
 
-      /* Set the screen height to the value it had before this function.  */
-      if (previous_frame_lines != FRAME_LINES (f)
-         || previous_frame_cols != FRAME_COLS (f))
-       change_frame_size (f, previous_frame_lines, previous_frame_cols,
-                          0, 0, 0);
-#if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
+      /* Set the frame size to the value it had before this function.  */
+      if (previous_frame_text_width != FRAME_TEXT_WIDTH (f)
+         || previous_frame_text_height != FRAME_TEXT_HEIGHT (f))
+       change_frame_size (f, previous_frame_text_width,
+                          previous_frame_text_height, 0, 0, 0, 1);
+
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
-       x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
-                             make_number (0));
+       {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (FRAME_WINDOW_P (f))
+           x_set_menu_bar_lines (f,
+                                 make_number (previous_frame_menu_bar_lines),
+                                 make_number (0));
+         else  /* TTY or MSDOS */
+#endif
+           set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
+                               make_number (0));
+       }
 #ifdef HAVE_WINDOW_SYSTEM
       if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
        x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
                              make_number (0));
-#endif
 #endif
 
       /* Now, free glyph matrices in windows that were not reused.  */
       for (i = n = 0; i < n_leaf_windows; ++i)
        {
-         if (NILP (leaf_windows[i]->buffer))
-           {
-             /* Assert it's not reused as a combination.  */
-             eassert (NILP (leaf_windows[i]->hchild)
-                      && NILP (leaf_windows[i]->vchild));
-             free_window_matrices (leaf_windows[i]);
-           }
-         else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
+         if (NILP (leaf_windows[i]->contents))
+           free_window_matrices (leaf_windows[i]);
+         else if (EQ (leaf_windows[i]->contents, new_current_buffer))
            ++n;
        }
 
-      adjust_glyphs (f);
+      adjust_frame_glyphs (f);
       unblock_input ();
 
       /* Scan dead buffer windows.  */
@@ -5878,6 +6254,20 @@ the return value is nil.  Otherwise the value is t.  */)
            delete_deletable_window (window);
        }
 
+      /* In the following call to `select-window', prevent "swapping out
+        point" in the old selected window using the buffer that has
+        been restored into it.  We already swapped out that point from
+        that window's old buffer.  */
+      /* This `select_window' calls record_buffer which calls Fdelq which
+        invokes QUIT, so we do it here at the end rather than earlier,
+        to minimize the risk of interrupting the Fset_window_configuration
+        in an inconsistent state (e.g. before frame-focus redirection is
+        canceled).  */
+      select_window (data->current_window, Qnil, 1);
+      BVAR (XBUFFER (XWINDOW (selected_window)->contents),
+           last_selected_window)
+       = selected_window;
+
       /* Fselect_window will have made f the selected frame, so we
         reselect the proper frame here.  Fhandle_switch_frame will change the
         selected window too, but that doesn't make the call to
@@ -5894,7 +6284,7 @@ the return value is nil.  Otherwise the value is t.  */)
       Fset_buffer (new_current_buffer);
       /* If the new current buffer doesn't appear in the selected
         window, go to its old point (see bug#12208).  */
-      if (!EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
+      if (!EQ (XWINDOW (data->current_window)->contents, new_current_buffer))
        Fgoto_char (make_number (old_point));
     }
 
@@ -5904,9 +6294,17 @@ the return value is nil.  Otherwise the value is t.  */)
   return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 
+void
+restore_window_configuration (Lisp_Object configuration)
+{
+  Fset_window_configuration (configuration);
+}
+
+
+/* If WINDOW is an internal window, recursively delete all child windows
+   reachable via the next and contents slots of WINDOW.  Otherwise setup
+   WINDOW to not show any buffer.  */
 
-/* Recursively delete all child windows reachable via the next, vchild,
-   and hchild slots of WINDOW.  */
 void
 delete_all_child_windows (Lisp_Object window)
 {
@@ -5918,24 +6316,20 @@ delete_all_child_windows (Lisp_Object window)
     /* Delete WINDOW's siblings (we traverse postorderly).  */
     delete_all_child_windows (w->next);
 
-  /* See Fset_window_configuration for excuse.  */
-  wset_total_lines (w, w->buffer);
-
-  if (!NILP (w->vchild))
-    {
-      delete_all_child_windows (w->vchild);
-      wset_vchild (w, Qnil);
-    }
-  else if (!NILP (w->hchild))
+  if (WINDOWP (w->contents))
     {
-      delete_all_child_windows (w->hchild);
-      wset_hchild (w, Qnil);
+      delete_all_child_windows (w->contents);
+      wset_combination (w, 0, Qnil);
     }
-  else if (!NILP (w->buffer))
+  else if (BUFFERP (w->contents))
     {
       unshow_buffer (w);
       unchain_marker (XMARKER (w->pointm));
       unchain_marker (XMARKER (w->start));
+      /* Since combination limit makes sense for an internal windows
+        only, we use this slot to save the buffer for the sake of
+        possible resurrection in Fset_window_configuration.  */
+      wset_combination_limit (w, w->contents);
       wset_buffer (w, Qnil);
     }
 
@@ -5948,10 +6342,8 @@ count_windows (register struct window *window)
   register int count = 1;
   if (!NILP (window->next))
     count += count_windows (XWINDOW (window->next));
-  if (!NILP (window->vchild))
-    count += count_windows (XWINDOW (window->vchild));
-  if (!NILP (window->hchild))
-    count += count_windows (XWINDOW (window->hchild));
+  if (WINDOWP (window->contents))
+    count += count_windows (XWINDOW (window->contents));
   return count;
 }
 
@@ -5963,10 +6355,8 @@ get_leaf_windows (struct window *w, struct window **flat, int i)
 {
   while (w)
     {
-      if (!NILP (w->hchild))
-       i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
-      else if (!NILP (w->vchild))
-       i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
+      if (WINDOWP (w->contents))
+       i = get_leaf_windows (XWINDOW (w->contents), flat, i);
       else
        flat[i++] = w;
 
@@ -6006,8 +6396,7 @@ get_phys_cursor_glyph (struct window *w)
        hpos = row->used[TEXT_AREA] - 1;
     }
 
-  if (row->used[TEXT_AREA] > hpos
-      && 0 <= hpos)
+  if (0 <= hpos && hpos < row->used[TEXT_AREA])
     glyph = row->glyphs[TEXT_AREA] + hpos;
   else
     glyph = NULL;
@@ -6023,29 +6412,33 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
   register struct window *w;
   register Lisp_Object tem, pers, par;
 
-  for (;!NILP (window); window = w->next)
+  for (; !NILP (window); window = w->next)
     {
       p = SAVED_WINDOW_N (vector, i);
       w = XWINDOW (window);
 
       wset_temslot (w, make_number (i)); i++;
       p->window = window;
-      p->buffer = w->buffer;
-      p->left_col = w->left_col;
-      p->top_line = w->top_line;
-      p->total_cols = w->total_cols;
-      p->total_lines = w->total_lines;
+      p->buffer = (WINDOW_LEAF_P (w) ? w->contents : Qnil);
+      p->pixel_left = make_number (w->pixel_left);
+      p->pixel_top = make_number (w->pixel_top);
+      p->pixel_width = make_number (w->pixel_width);
+      p->pixel_height = make_number (w->pixel_height);
+      p->left_col = make_number (w->left_col);
+      p->top_line = make_number (w->top_line);
+      p->total_cols = make_number (w->total_cols);
+      p->total_lines = make_number (w->total_lines);
       p->normal_cols = w->normal_cols;
       p->normal_lines = w->normal_lines;
       XSETFASTINT (p->hscroll, w->hscroll);
       XSETFASTINT (p->min_hscroll, w->min_hscroll);
       p->display_table = w->display_table;
-      p->left_margin_cols = w->left_margin_cols;
-      p->right_margin_cols = w->right_margin_cols;
-      p->left_fringe_width = w->left_fringe_width;
-      p->right_fringe_width = w->right_fringe_width;
+      p->left_margin_cols = make_number (w->left_margin_cols);
+      p->right_margin_cols = make_number (w->right_margin_cols);
+      p->left_fringe_width = make_number (w->left_fringe_width);
+      p->right_fringe_width = make_number (w->right_fringe_width);
       p->fringes_outside_margins = w->fringes_outside_margins ? Qt : Qnil;
-      p->scroll_bar_width = w->scroll_bar_width;
+      p->scroll_bar_width = make_number (w->scroll_bar_width);
       p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
       p->dedicated = w->dedicated;
       p->combination_limit = w->combination_limit;
@@ -6097,15 +6490,15 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
            }
        }
 
-      if (!NILP (w->buffer))
+      if (BUFFERP (w->contents))
        {
          /* Save w's value of point in the window configuration.  If w
             is the selected window, then get the value of point from
             the buffer; pointm is garbage in the selected window.  */
          if (EQ (window, selected_window))
-           p->pointm = build_marker (XBUFFER (w->buffer),
-                                     BUF_PT (XBUFFER (w->buffer)),
-                                     BUF_PT_BYTE (XBUFFER (w->buffer)));
+           p->pointm = build_marker (XBUFFER (w->contents),
+                                     BUF_PT (XBUFFER (w->contents)),
+                                     BUF_PT_BYTE (XBUFFER (w->contents)));
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
          XMARKER (p->pointm)->insertion_type
@@ -6114,7 +6507,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
          p->start = Fcopy_marker (w->start, Qnil);
          p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil;
 
-         tem = BVAR (XBUFFER (w->buffer), mark);
+         tem = BVAR (XBUFFER (w->contents), mark);
          p->mark = Fcopy_marker (tem, Qnil);
        }
       else
@@ -6135,10 +6528,8 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
       else
        p->prev = XWINDOW (w->prev)->temslot;
 
-      if (!NILP (w->vchild))
-       i = save_window_save (w->vchild, vector, i);
-      if (!NILP (w->hchild))
-       i = save_window_save (w->hchild, vector, i);
+      if (WINDOWP (w->contents))
+       i = save_window_save (w->contents, vector, i);
     }
 
   return i;
@@ -6172,6 +6563,10 @@ saved by this function.  */)
   data->frame_lines = FRAME_LINES (f);
   data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
   data->frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+  data->frame_text_width = FRAME_TEXT_WIDTH (f);
+  data->frame_text_height = FRAME_TEXT_HEIGHT (f);
+  data->frame_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f);
+  data->frame_tool_bar_height = FRAME_TOOL_BAR_HEIGHT (f);
   data->selected_frame = selected_frame;
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
@@ -6188,11 +6583,46 @@ saved by this function.  */)
   XSETWINDOW_CONFIGURATION (tem, data);
   return (tem);
 }
+
+/* Called after W's margins, fringes or scroll bars was adjusted.  */
+
+static void
+apply_window_adjustment (struct window *w)
+{
+  eassert (w);
+  adjust_window_margins (w);
+  clear_glyph_matrix (w->current_matrix);
+  w->window_end_valid = 0;
+  windows_or_buffers_changed = 40;
+  adjust_frame_glyphs (XFRAME (WINDOW_FRAME (w)));
+}
+
 \f
 /***********************************************************************
                            Marginal Areas
  ***********************************************************************/
 
+static struct window *
+set_window_margins (struct window *w, Lisp_Object left_width,
+                   Lisp_Object right_width)
+{
+  int left, right;
+
+  /* FIXME: what about margins that are too wide?  */
+  left = (NILP (left_width) ? 0
+         : (CHECK_NATNUM (left_width), XINT (left_width)));
+  right = (NILP (right_width) ? 0
+          : (CHECK_NATNUM (right_width), XINT (right_width)));
+
+  if (w->left_margin_cols != left || w->right_margin_cols != right)
+    {
+      w->left_margin_cols = left;
+      w->right_margin_cols = right;
+      return w;
+    }
+  return NULL;
+}
+
 DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
        2, 3, 0,
        doc: /* Set width of marginal areas of window WINDOW.
@@ -6201,41 +6631,14 @@ WINDOW must be a live window and defaults to the selected one.
 Second arg LEFT-WIDTH specifies the number of character cells to
 reserve for the left marginal area.  Optional third arg RIGHT-WIDTH
 does the same for the right marginal area.  A nil width parameter
-means no margin.  */)
+means no margin.
+
+Return t if any margin was actually changed and nil otherwise.  */)
   (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width)
 {
-  struct window *w = decode_live_window (window);
-
-  /* Translate negative or zero widths to nil.
-     Margins that are too wide have to be checked elsewhere.  */
-
-  if (!NILP (left_width))
-    {
-      CHECK_NUMBER (left_width);
-      if (XINT (left_width) <= 0)
-       left_width = Qnil;
-    }
-
-  if (!NILP (right_width))
-    {
-      CHECK_NUMBER (right_width);
-      if (XINT (right_width) <= 0)
-       right_width = Qnil;
-    }
-
-  if (!EQ (w->left_margin_cols, left_width)
-      || !EQ (w->right_margin_cols, right_width))
-    {
-      wset_left_margin_cols (w, left_width);
-      wset_right_margin_cols (w, right_width);
-
-      adjust_window_margins (w);
-
-      ++windows_or_buffers_changed;
-      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
-    }
-
-  return Qnil;
+  struct window *w = set_window_margins (decode_live_window (window),
+                                        left_width, right_width);
+  return w ? (apply_window_adjustment (w), Qt) : Qnil;
 }
 
 
@@ -6250,7 +6653,10 @@ as nil.  */)
   (Lisp_Object window)
 {
   struct window *w = decode_live_window (window);
-  return Fcons (w->left_margin_cols, w->right_margin_cols);
+  return Fcons (w->left_margin_cols
+               ? make_number (w->left_margin_cols) : Qnil,
+               w->right_margin_cols
+               ? make_number (w->right_margin_cols) : Qnil);
 }
 
 
@@ -6259,6 +6665,31 @@ as nil.  */)
                            Fringes
  ***********************************************************************/
 
+static struct window *
+set_window_fringes (struct window *w, Lisp_Object left_width,
+                   Lisp_Object right_width, Lisp_Object outside_margins)
+{
+  int left, right, outside = !NILP (outside_margins);
+
+  left = (NILP (left_width) ? -1
+         : (CHECK_NATNUM (left_width), XINT (left_width)));
+  right = (NILP (right_width) ? -1
+          : (CHECK_NATNUM (right_width), XINT (right_width)));
+
+  /* Do nothing on a tty or if nothing to actually change.  */
+  if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
+      && (w->left_fringe_width != left
+         || w->right_fringe_width != right
+         || w->fringes_outside_margins != outside))
+    {
+      w->left_fringe_width = left;
+      w->right_fringe_width = right;
+      w->fringes_outside_margins = outside;
+      return w;
+    }
+  return NULL;
+}
+
 DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
        2, 4, 0,
        doc: /* Set the fringe widths of window WINDOW.
@@ -6271,37 +6702,16 @@ frame's default fringe width.  Default fringe widths can be set with
 the command `set-fringe-style'.
 If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
 outside of the display margins.  By default, fringes are drawn between
-display marginal areas and the text area.  */)
-  (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width, Lisp_Object outside_margins)
-{
-  struct window *w = decode_live_window (window);
-  int outside = !NILP (outside_margins);
-
-  if (!NILP (left_width))
-    CHECK_NATNUM (left_width);
-  if (!NILP (right_width))
-    CHECK_NATNUM (right_width);
-
-  /* Do nothing on a tty.  */
-  if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
-      && (!EQ (w->left_fringe_width, left_width)
-         || !EQ (w->right_fringe_width, right_width)
-         || w->fringes_outside_margins != outside))
-    {
-      wset_left_fringe_width (w, left_width);
-      wset_right_fringe_width (w, right_width);
-      w->fringes_outside_margins = outside;
-
-      adjust_window_margins (w);
-
-      clear_glyph_matrix (w->current_matrix);
-      w->window_end_valid = 0;
-
-      ++windows_or_buffers_changed;
-      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
-    }
+display marginal areas and the text area.
 
-  return Qnil;
+Return t if any fringe was actually changed and nil otherwise.  */)
+  (Lisp_Object window, Lisp_Object left_width,
+   Lisp_Object right_width, Lisp_Object outside_margins)
+{
+  struct window *w
+    = set_window_fringes (decode_live_window (window),
+                         left_width, right_width, outside_margins);
+  return w ? (apply_window_adjustment (w), Qt) : Qnil;
 }
 
 
@@ -6326,29 +6736,14 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
                            Scroll bars
  ***********************************************************************/
 
-DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars,
-       Sset_window_scroll_bars, 2, 4, 0,
-       doc: /* Set width and type of scroll bars of window WINDOW.
-WINDOW must be a live window and defaults to the selected one.
-
-Second parameter WIDTH specifies the pixel width for the scroll bar;
-this is automatically adjusted to a multiple of the frame column width.
-Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
-bar: left, right, or nil.
-If WIDTH is nil, use the frame's scroll-bar width.
-If VERTICAL-TYPE is t, use the frame's scroll-bar type.
-Fourth parameter HORIZONTAL-TYPE is currently unused.  */)
-  (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, Lisp_Object horizontal_type)
+static struct window *
+set_window_scroll_bars (struct window *w, Lisp_Object width,
+                       Lisp_Object vertical_type, Lisp_Object horizontal_type)
 {
-  struct window *w = decode_live_window (window);
-
-  if (!NILP (width))
-    {
-      CHECK_RANGED_INTEGER (width, 0, INT_MAX);
+  int iwidth = (NILP (width) ? -1 : (CHECK_NATNUM (width), XINT (width)));
 
-      if (XINT (width) == 0)
-       vertical_type = Qnil;
-    }
+  if (iwidth == 0)
+    vertical_type = Qnil;
 
   if (!(NILP (vertical_type)
        || EQ (vertical_type, Qleft)
@@ -6356,22 +6751,36 @@ Fourth parameter HORIZONTAL-TYPE is currently unused.  */)
        || EQ (vertical_type, Qt)))
     error ("Invalid type of vertical scroll bar");
 
-  if (!EQ (w->scroll_bar_width, width)
+  if (w->scroll_bar_width != iwidth
       || !EQ (w->vertical_scroll_bar_type, vertical_type))
     {
-      wset_scroll_bar_width (w, width);
+      w->scroll_bar_width = iwidth;
       wset_vertical_scroll_bar_type (w, vertical_type);
+      return w;
+    }
+  return NULL;
+}
 
-      adjust_window_margins (w);
-
-      clear_glyph_matrix (w->current_matrix);
-      w->window_end_valid = 0;
+DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars,
+       Sset_window_scroll_bars, 2, 4, 0,
+       doc: /* Set width and type of scroll bars of window WINDOW.
+WINDOW must be a live window and defaults to the selected one.
 
-      ++windows_or_buffers_changed;
-      adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
-    }
+Second parameter WIDTH specifies the pixel width for the scroll bar.
+Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
+bar: left, right, or nil.
+If WIDTH is nil, use the frame's scroll-bar width.
+If VERTICAL-TYPE is t, use the frame's scroll-bar type.
+Fourth parameter HORIZONTAL-TYPE is currently unused.
 
-  return Qnil;
+Return t if scroll bars were actually changed and nil otherwise.  */)
+  (Lisp_Object window, Lisp_Object width,
+   Lisp_Object vertical_type, Lisp_Object horizontal_type)
+{
+  struct window *w
+    = set_window_scroll_bars (decode_live_window (window),
+                             width, vertical_type, horizontal_type);
+  return w ? (apply_window_adjustment (w), Qt) : Qnil;
 }
 
 
@@ -6452,10 +6861,10 @@ If PIXELS-P is non-nil, the return value is VSCROLL.  */)
          /* Adjust glyph matrix of the frame if the virtual display
             area becomes larger than before.  */
          if (w->vscroll < 0 && w->vscroll < old_dy)
-           adjust_glyphs (f);
+           adjust_frame_glyphs (f);
 
          /* Prevent redisplay shortcuts.  */
-         XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+         XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1;
        }
     }
 
@@ -6489,10 +6898,8 @@ foreach_window_1 (struct window *w, int (*fn) (struct window *, void *), void *u
 
   for (cont = 1; w && cont;)
     {
-      if (!NILP (w->hchild))
-       cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
-      else if (!NILP (w->vchild))
-       cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
+      if (WINDOWP (w->contents))
+       cont = foreach_window_1 (XWINDOW (w->contents), fn, user_data);
       else
        cont = fn (w, user_data);
 
@@ -6502,38 +6909,6 @@ foreach_window_1 (struct window *w, int (*fn) (struct window *, void *), void *u
   return cont;
 }
 
-
-/* Freeze or unfreeze the window start of W unless it is a
-   mini-window or the selected window.  FREEZE_P non-null means freeze
-   the window start.  */
-
-static int
-freeze_window_start (struct window *w, void *freeze_p)
-{
-  if (MINI_WINDOW_P (w)
-      || (WINDOWP (selected_window) /* Can be nil in corner cases.  */
-         && (w == XWINDOW (selected_window)
-             || (MINI_WINDOW_P (XWINDOW (selected_window))
-                 && ! NILP (Vminibuf_scroll_window)
-                 && w == XWINDOW (Vminibuf_scroll_window)))))
-    freeze_p = NULL;
-
-  w->frozen_window_start_p = freeze_p != NULL;
-  return 1;
-}
-
-
-/* Freeze or unfreeze the window starts of all leaf windows on frame
-   F, except the selected window and a mini-window.  FREEZE_P non-zero
-   means freeze the window start.  */
-
-void
-freeze_window_starts (struct frame *f, bool freeze_p)
-{
-  foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
-}
-
-\f
 /***********************************************************************
                            Initialization
  ***********************************************************************/
@@ -6593,6 +6968,10 @@ compare_window_configurations (Lisp_Object configuration1,
          != EQ (d2->current_window, sw2->window)
          /* Windows' buffers must match.  */
          || !EQ (sw1->buffer, sw2->buffer)
+         || !EQ (sw1->pixel_left, sw2->pixel_left)
+         || !EQ (sw1->pixel_top, sw2->pixel_top)
+         || !EQ (sw1->pixel_height, sw2->pixel_height)
+         || !EQ (sw1->pixel_width, sw2->pixel_width)
          || !EQ (sw1->left_col, sw2->left_col)
          || !EQ (sw1->top_line, sw2->top_line)
          || !EQ (sw1->total_cols, sw2->total_cols)
@@ -6642,7 +7021,6 @@ init_window_once (void)
   Vterminal_frame = selected_frame;
   minibuf_window = f->minibuffer_window;
   selected_window = f->selected_window;
-  last_nonminibuf_frame = f;
 
   window_initialized = 1;
 }
@@ -6672,6 +7050,7 @@ syms_of_window (void)
   DEFSYM (Qdelete_window, "delete-window");
   DEFSYM (Qwindow_resize_root_window, "window--resize-root-window");
   DEFSYM (Qwindow_resize_root_window_vertically, "window--resize-root-window-vertically");
+  DEFSYM (Qwindow_pixel_to_total, "window--pixel-to-total");
   DEFSYM (Qsafe, "safe");
   DEFSYM (Qdisplay_buffer, "display-buffer");
   DEFSYM (Qreplace_buffer_in_windows, "replace-buffer-in-windows");
@@ -6830,6 +7209,18 @@ Parameters not saved by `current-window-configuration' or
 respectively are not installed by `window-state-put'.  */);
   Vwindow_persistent_parameters = list1 (Fcons (Qclone_of, Qt));
 
+  DEFVAR_BOOL ("window-resize-pixelwise", window_resize_pixelwise,
+              doc: /*  Non-nil means resizing windows works pixelwise.
+Functions currently affected by this option are `split-window',
+`maximize-window', `minimize-window', `fit-window-to-buffer' and
+`fit-frame-to-buffer' and all functions symmetrically resizing a
+parent window.
+
+Note that when a frame's pixel size is not a multiple of the
+frame's character size, at least one window may get resized
+pixelwise even if this option is nil.  */);
+  window_resize_pixelwise = 0;
+
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);
@@ -6852,16 +7243,23 @@ respectively are not installed by `window-state-put'.  */);
   defsubr (&Swindow_combination_limit);
   defsubr (&Sset_window_combination_limit);
   defsubr (&Swindow_use_time);
-  defsubr (&Swindow_top_line);
-  defsubr (&Swindow_left_column);
-  defsubr (&Swindow_total_height);
+  defsubr (&Swindow_pixel_width);
+  defsubr (&Swindow_pixel_height);
   defsubr (&Swindow_total_width);
+  defsubr (&Swindow_total_height);
   defsubr (&Swindow_normal_size);
+  defsubr (&Swindow_new_pixel);
   defsubr (&Swindow_new_total);
   defsubr (&Swindow_new_normal);
+  defsubr (&Swindow_pixel_left);
+  defsubr (&Swindow_pixel_top);
+  defsubr (&Swindow_left_column);
+  defsubr (&Swindow_top_line);
+  defsubr (&Sset_window_new_pixel);
   defsubr (&Sset_window_new_total);
   defsubr (&Sset_window_new_normal);
   defsubr (&Swindow_resize_apply);
+  defsubr (&Swindow_resize_apply_total);
   defsubr (&Swindow_body_height);
   defsubr (&Swindow_body_width);
   defsubr (&Swindow_hscroll);
@@ -6871,6 +7269,10 @@ respectively are not installed by `window-state-put'.  */);
   defsubr (&Swindow_edges);
   defsubr (&Swindow_pixel_edges);
   defsubr (&Swindow_absolute_pixel_edges);
+  defsubr (&Swindow_mode_line_height);
+  defsubr (&Swindow_header_line_height);
+  defsubr (&Swindow_right_divider_width);
+  defsubr (&Swindow_bottom_divider_width);
   defsubr (&Swindow_inside_edges);
   defsubr (&Swindow_inside_pixel_edges);
   defsubr (&Swindow_inside_absolute_pixel_edges);
@@ -6893,6 +7295,7 @@ respectively are not installed by `window-state-put'.  */);
   defsubr (&Sresize_mini_window_internal);
   defsubr (&Sset_window_buffer);
   defsubr (&Srun_window_configuration_change_hook);
+  defsubr (&Srun_window_scroll_functions);
   defsubr (&Sselect_window);
   defsubr (&Sforce_window_update);
   defsubr (&Ssplit_window_internal);
@@ -6904,6 +7307,7 @@ respectively are not installed by `window-state-put'.  */);
   defsubr (&Sscroll_other_window);
   defsubr (&Sminibuffer_selected_window);
   defsubr (&Srecenter);
+  defsubr (&Swindow_text_width);
   defsubr (&Swindow_text_height);
   defsubr (&Smove_to_window_line);
   defsubr (&Swindow_configuration_p);