use dynwind_begin and dynwind_end
[bpt/emacs.git] / src / window.c
index bc0adaf..2fa89e8 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985-1987, 1993-1998, 2000-2013 Free Software
+   Copyright (C) 1985-1987, 1993-1998, 2000-2014 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -27,6 +27,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "buffer.h"
 #include "keyboard.h"
 #include "keymap.h"
+#include "menu.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
@@ -51,8 +52,11 @@ 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 Lisp_Object Qfloor, Qceiling;
+static Lisp_Object Qwindow_point_insertion_type;
 
 static int displayed_window_lines (struct window *);
 static int count_windows (struct window *);
@@ -60,7 +64,6 @@ static int get_leaf_windows (struct window *, struct window **, int);
 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 Lisp_Object window_list (void);
 static int add_window_to_list (struct window *, void *);
 static Lisp_Object next_window (Lisp_Object, Lisp_Object,
                                 Lisp_Object, int);
@@ -75,6 +78,7 @@ 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);
 
@@ -113,13 +117,13 @@ Lisp_Object minibuf_selected_window;
 /* Hook run at end of temp_output_buffer_show.  */
 static Lisp_Object Qtemp_buffer_show_hook;
 
-/* Nonzero after init_window_once has finished.  */
-static int window_initialized;
+/* Incremented for each window created.  */
+static int sequence_number;
 
 /* Hook to run when window config changes.  */
 static Lisp_Object Qwindow_configuration_change_hook;
 
-/* Used by the function window_scroll_pixel_based */
+/* Used by the function window_scroll_pixel_based */
 static int window_scroll_pixel_based_preserve_x;
 static int window_scroll_pixel_based_preserve_y;
 
@@ -482,6 +486,15 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
        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));
+      wset_redisplay (w);
+    }
+  else
+    redisplay_other_windows ();
+
   sf = SELECTED_FRAME ();
   if (XFRAME (WINDOW_FRAME (w)) != sf)
     {
@@ -500,7 +513,6 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
 
   select_window_1 (window, inhibit_point_swap);
   bset_last_selected_window (XBUFFER (w->contents), window);
-  windows_or_buffers_changed = 24;
 
  record_and_return:
   /* record_buffer can run QUIT, so make sure it is run only after we have
@@ -546,7 +558,7 @@ select_window_1 (Lisp_Object window, bool inhibit_point_swap)
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
        doc: /* Select WINDOW which must be a live window.
 Also make WINDOW's frame the selected frame and WINDOW that frame's
-selected window.  In addition, make WINDOW's buffer current and set that
+selected window.  In addition, make WINDOW's buffer current and set its
 buffer's value of `point' to the value of WINDOW's `window-point'.
 Return WINDOW.
 
@@ -554,8 +566,17 @@ Optional second arg NORECORD non-nil means do not put this buffer at the
 front of the buffer list and do not make this window the most recently
 selected one.
 
-Note that the main editor command loop sets the current buffer to the
-buffer of the selected window before each command.  */)
+Run `buffer-list-update-hook' unless NORECORD is non-nil.  Note that
+applications and internal routines often select a window temporarily for
+various purposes; mostly, to simplify coding.  As a rule, such
+selections should be not recorded and therefore will not pollute
+`buffer-list-update-hook'.  Selections that "really count" are those
+causing a visible change in the next redisplay of WINDOW's frame and
+should be always recorded.  So if you think of running a function each
+time a window gets selected put it on `buffer-list-update-hook'.
+
+Also note that the main editor command loop sets the current buffer to
+the buffer of the selected window before each command.  */)
   (register Lisp_Object window, Lisp_Object norecord)
 {
   return select_window (window, norecord, 0);
@@ -669,34 +690,102 @@ selected one.  */)
   return make_number (decode_live_window (window)->use_time);
 }
 \f
-DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 1, 0,
-       doc: /* Return the total height, in lines, of window WINDOW.
+DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
+       doc: /* Return the width of window WINDOW in pixels.
 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, the total height is the height
-of the screen areas spanned by its children.
+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 height of window WINDOW in pixels.
+WINDOW must be a valid window and defaults to the selected one.
 
-On a graphical display, this total height is reported as an
-integer multiple of the default character height.  */)
+The return value includes the mode line and header line and the bottom
+divider, 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)->total_lines);
+  return make_number (decode_valid_window (window)->pixel_height);
 }
 
-DEFUN ("window-total-width", Fwindow_total_width, Swindow_total_width, 0, 1, 0,
-       doc: /* Return the total width, in columns, of window WINDOW.
+DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 2, 0,
+       doc: /* Return the height of window WINDOW in lines.
 WINDOW must be a valid window and defaults to the selected one.
 
-The return value includes any vertical dividers or scroll bars
-belonging to WINDOW.  If WINDOW is an internal window, the total width
-is the width of the screen areas spanned by its children.
+The return value includes the heights of WINDOW's mode and header line
+and its bottom divider, if any.  If WINDOW is an internal window, the
+total height is the height of the screen areas spanned by its children.
 
-On a graphical display, this total width is reported as an
-integer multiple of the default character width.  */)
-  (Lisp_Object window)
+If WINDOW's pixel height is not an integral multiple of its frame's
+character height, the number of lines occupied by WINDOW is rounded
+internally.  This is done in a way such that, if WINDOW is a parent
+window, the sum of the total heights of all its children internally
+equals the total height of WINDOW.
+
+If the optional argument ROUND is `ceiling', return the smallest integer
+larger than WINDOW's pixel height divided by the character height of
+WINDOW's frame.  ROUND `floor' means to return the largest integer
+smaller than WINDOW's pixel height divided by the character height of
+WINDOW's frame.  Any other value of ROUND means to return the internal
+total height of WINDOW.  */)
+  (Lisp_Object window, Lisp_Object round)
+{
+  struct window *w = decode_valid_window (window);
+
+  if (! EQ (round, Qfloor) && ! EQ (round, Qceiling))
+    return make_number (w->total_lines);
+  else
+    {
+      int unit = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w));
+
+      return make_number (EQ (round, Qceiling)
+                         ? ((w->pixel_height + unit - 1) /unit)
+                         : (w->pixel_height / unit));
+    }
+}
+
+DEFUN ("window-total-width", Fwindow_total_width, Swindow_total_width, 0, 2, 0,
+       doc: /* Return the total width of window WINDOW in columns.
+WINDOW must be a valid window and defaults to the selected one.
+
+The return value includes the widths of WINDOW's fringes, margins,
+scroll bars and its right divider, if any.  If WINDOW is an internal
+window, the total width is the width of the screen areas spanned by its
+children.
+
+If WINDOW's pixel width is not an integral multiple of its frame's
+character width, the number of lines occupied by WINDOW is rounded
+internally.  This is done in a way such that, if WINDOW is a parent
+window, the sum of the total widths of all its children internally
+equals the total width of WINDOW.
+
+If the optional argument ROUND is `ceiling', return the smallest integer
+larger than WINDOW's pixel width divided by the character width of
+WINDOW's frame.  ROUND `floor' means to return the largest integer
+smaller than WINDOW's pixel width divided by the character width of
+WINDOW's frame.  Any other value of ROUND means to return the internal
+total width of WINDOW.  */)
+  (Lisp_Object window, Lisp_Object round)
 {
-  return make_number (decode_valid_window (window)->total_cols);
+  struct window *w = decode_valid_window (window);
+
+  if (! EQ (round, Qfloor) && ! EQ (round, Qceiling))
+    return make_number (w->total_cols);
+  else
+    {
+      int unit = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w));
+
+      return make_number (EQ (round, Qceiling)
+                         ? ((w->pixel_width + unit - 1) /unit)
+                         : (w->pixel_width / unit));
+    }
 }
 
 DEFUN ("window-new-total", Fwindow_new_total, Swindow_new_total, 0, 1, 0,
@@ -726,6 +815,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
@@ -750,79 +863,132 @@ WINDOW must be a valid window and defaults to the selected one.  */)
   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.  */
-
+/* Return the number of lines/pixels of W's body.  Don't count any mode
+   or header line or horizontal divider of W.  Rounds down to nearest
+   integer when not working pixelwise. */
 static int
-window_body_lines (struct window *w)
+window_body_height (struct window *w, bool pixelwise)
 {
-  int height = w->total_lines;
+  int height = (w->pixel_height
+               - WINDOW_HEADER_LINE_HEIGHT (w)
+               - WINDOW_MODE_LINE_HEIGHT (w)
+               - WINDOW_BOTTOM_DIVIDER_WIDTH (w));
 
-  if (!MINI_WINDOW_P (w))
-    {
-      if (WINDOW_WANTS_MODELINE_P (w))
-       --height;
-      if (WINDOW_WANTS_HEADER_LINE_P (w))
-       --height;
-    }
-
-  return height;
+  /* Don't return a negative value.  */
+  return max (pixelwise
+             ? height
+             : height / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)),
+             0);
 }
 
-/* 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.  */
-
+/* Return the number of columns/pixels of W's body.  Don't count columns
+   occupied by the scroll bar or the divider/vertical bar separating W
+   from its right sibling or margins.  On window-systems don't count
+   fringes either.  Round down to nearest integer when not working
+   pixelwise.  */
 int
-window_body_cols (struct window *w)
+window_body_width (struct window *w, bool pixelwise)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  int width = 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;
 
-  /* Display margins cannot be used for normal text.  */
-  width -= WINDOW_LEFT_MARGIN_COLS (w) + WINDOW_RIGHT_MARGIN_COLS (w);
-
-  if (FRAME_WINDOW_P (f))
-    /* On window-systems, fringes cannot be used for normal text.  */
-    width -= WINDOW_FRINGE_COLS (w);
-
-  return width;
+  int width = (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))
+                    /* A vertical bar is either 1 or 0.  */
+                    ? 1 : 0))
+               - WINDOW_MARGINS_WIDTH (w)
+               - (FRAME_WINDOW_P (f)
+                  ? WINDOW_FRINGES_WIDTH (w)
+                  : 0));
+
+  /* Don't return a negative value.  */
+  return max (pixelwise
+             ? width
+             : width / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)),
+             0);
+}
+
+DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 2, 0,
+       doc: /* Return the height of WINDOW's text area.
+WINDOW must be a live window and defaults to the selected one.  Optional
+argument PIXELWISE non-nil means return the height of WINDOW's text area
+in pixels.  The return value does not include the mode line or header
+line or any horizontal divider.
+
+If PIXELWISE is nil, return the largest integer smaller than WINDOW's
+pixel height divided by the character height of WINDOW's frame.  This
+means that if a line at the bottom of the text area is only partially
+visible, that line is not counted.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
+{
+  return make_number (window_body_height (decode_live_window (window),
+                                         NILP (pixelwise) ? 0 : 1));
+}
+
+DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
+       doc: /* Return the width of WINDOW's text area.
+WINDOW must be a live window and defaults to the selected one.  Optional
+argument PIXELWISE non-nil means return the width in pixels.  The return
+value does not include any vertical dividers, fringes or marginal areas,
+or scroll bars.
+
+If PIXELWISE is nil, return the largest integer smaller than WINDOW's
+pixel width divided by the character width of WINDOW's frame.  This
+means that if a column at the right of the text area is only partially
+visible, that column is not counted.  */)
+  (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 pixels of WINDOW's mode-line.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return (make_number (WINDOW_MODE_LINE_HEIGHT (decode_live_window (window))));
 }
 
-DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 1, 0,
-       doc: /* Return the height, in lines, 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 pixels 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 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'.  */)
+DEFUN ("window-right-divider-width", Fwindow_right_divider_width,
+       Swindow_right_divider_width, 0, 1, 0,
+       doc: /* Return the width in pixels of WINDOW's right divider.
+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_RIGHT_DIVIDER_WIDTH (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-bottom-divider-width", Fwindow_bottom_divider_width,
+       Swindow_bottom_divider_width, 0, 1, 0,
+       doc: /* Return the width in pixels of WINDOW's bottom divider.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return (make_number (WINDOW_BOTTOM_DIVIDER_WIDTH (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-scroll-bar-width", Fwindow_scroll_bar_width,
+       Swindow_scroll_bar_width, 0, 1, 0,
+       doc: /* Return the width in pixels of WINDOW's vertical scrollbar.
+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_SCROLL_BAR_AREA_WIDTH (decode_live_window (window))));
 }
 
 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
@@ -1072,11 +1238,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;
@@ -1104,25 +1274,41 @@ 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 the horizontal window divider (which prevails the vertical
+     divider)?  */
+  if (WINDOW_BOTTOM_DIVIDER_WIDTH (w) > 0
+      && y >= (bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+      && y <= bottom_y)
+    return ON_BOTTOM_DIVIDER;
+  /* On vertical window divider?  */
+  else if (!WINDOW_RIGHTMOST_P (w)
+          && WINDOW_RIGHT_DIVIDER_WIDTH (w) > 0
+          && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w)
+          && x <= right_x)
+    return ON_RIGHT_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
         resize windows horizontally in case we're using toolkit scroll
         bars.  Note: If scrollbars are on the left, the window that
         must be eventually resized is that on the left of WINDOW.  */
-      if ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
-          && !WINDOW_LEFTMOST_P (w)
-          && eabs (x - left_x) < grabbable_width)
-         || (!WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
-             && !WINDOW_RIGHTMOST_P (w)
-             && eabs (x - right_x) < grabbable_width))
+      if ((WINDOW_RIGHT_DIVIDER_WIDTH (w) == 0)
+         && ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+              && !WINDOW_LEFTMOST_P (w)
+              && eabs (x - left_x) < grabbable_width)
+             || (!WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+                 && !WINDOW_RIGHTMOST_P (w)
+                 && eabs (x - right_x) < grabbable_width)))
        return ON_VERTICAL_BORDER;
       else
        return part;
@@ -1133,7 +1319,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
     {
@@ -1154,6 +1340,7 @@ coordinates_in_window (register struct window *w, int x, int y)
   if (FRAME_WINDOW_P (f))
     {
       if (!w->pseudo_window_p
+         && WINDOW_RIGHT_DIVIDER_WIDTH (w) == 0
          && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
          && !WINDOW_RIGHTMOST_P (w)
          && (eabs (x - right_x) < grabbable_width))
@@ -1162,7 +1349,10 @@ coordinates_in_window (register struct window *w, int x, int y)
   /* Need to say "x > right_x" rather than >=, since on character
      terminals, the vertical line's x coordinate is right_x.  */
   else if (!w->pseudo_window_p
+          && WINDOW_RIGHT_DIVIDER_WIDTH (w) == 0
           && !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;
 
@@ -1173,8 +1363,8 @@ coordinates_in_window (register struct window *w, int x, int y)
              ? (x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
              : (x < left_x + lmargin_width)))
        return ON_LEFT_MARGIN;
-
-      return ON_LEFT_FRINGE;
+      else
+       return ON_LEFT_FRINGE;
     }
 
   if (x >= text_right)
@@ -1184,8 +1374,8 @@ coordinates_in_window (register struct window *w, int x, int y)
              ? (x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
              : (x >= right_x - rmargin_width)))
        return ON_RIGHT_MARGIN;
-
-      return ON_RIGHT_FRINGE;
+      else
+       return ON_RIGHT_FRINGE;
     }
 
   /* Everything special ruled out - must be on text area */
@@ -1204,6 +1394,8 @@ window_relative_x_coord (struct window *w, enum window_part part, int x)
     case ON_TEXT:
       return x - window_box_left (w, TEXT_AREA);
 
+    case ON_HEADER_LINE:
+    case ON_MODE_LINE:
     case ON_LEFT_FRINGE:
       return x - left_x;
 
@@ -1218,7 +1410,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))
@@ -1240,8 +1432,10 @@ measured in characters from the upper-left corner of the frame.
 frame.
 If COORDINATES are in the text portion of WINDOW,
    the coordinates relative to the window are returned.
+If they are in the bottom divider of WINDOW, `bottom-divider' is returned.
+If they are in the right divider of WINDOW, `right-divider' is returned.
 If they are in the mode line of WINDOW, `mode-line' is returned.
-If they are in the top mode line of WINDOW, `header-line' is returned.
+If they are in the header line of WINDOW, `header-line' is returned.
 If they are in the left fringe of WINDOW, `left-fringe' is returned.
 If they are in the right fringe of WINDOW, `right-fringe' is returned.
 If they are on the border between WINDOW and its right sibling,
@@ -1303,6 +1497,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 ();
     }
@@ -1553,7 +1753,7 @@ Return POS.  */)
       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 = 25;
+      wset_redisplay (w);
     }
 
   return pos;
@@ -1574,9 +1774,9 @@ overriding motion of point in order to display at this exact start.  */)
   if (NILP (noforce))
     w->force_start = 1;
   w->update_mode_line = 1;
-  if (w != XWINDOW (selected_window))
-    /* Enforce full redisplay.  FIXME: make it more selective.  */
-    windows_or_buffers_changed = 26;
+  /* Bug#15957.  */
+  w->window_end_valid = 0;
+  wset_redisplay (w);
 
   return pos;
 }
@@ -1995,6 +2195,10 @@ replace_window (Lisp_Object old, Lisp_Object new, int setflag)
 
   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;
@@ -2075,13 +2279,13 @@ recombine_windows (Lisp_Object window)
              wset_parent (c, parent);
 
              if (horflag)
-               wset_normal_cols (c,
-                                 make_float ((double) c->total_cols
-                                             / (double) p->total_cols));
+               wset_normal_cols
+                 (c, make_float ((double) c->pixel_width
+                                 / (double) p->pixel_width));
              else
-               wset_normal_lines (c,
-                                  make_float ((double) c->total_lines
-                                              / (double) p->total_lines));
+               wset_normal_lines
+                 (c, make_float ((double) c->pixel_height
+                                 / (double) p->pixel_height));
 
              if (NILP (c->next))
                {
@@ -2137,7 +2341,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))
@@ -2599,7 +2803,7 @@ window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frame
              {
                if (EQ (window, selected_window))
                  /* Preferably return the selected window.  */
-                 RETURN_UNGCPRO (window);
+                 return window;
                else if (EQ (XWINDOW (window)->frame, selected_frame)
                         && !frame_best_window_flag)
                  /* Prefer windows on the current frame (but don't
@@ -2712,9 +2916,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);
 }
 
 
@@ -2778,8 +2989,8 @@ window-start value is reasonable when this function is called.  */)
     {
       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)))
        {
@@ -2837,7 +3048,7 @@ window-start value is reasonable when this function is called.  */)
     }
   free_window_matrices (r);
 
-  windows_or_buffers_changed = 27;
+  fset_redisplay (f);
   Vwindow_list = Qnil;
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
   resize_failed = 0;
@@ -2845,16 +3056,23 @@ window-start value is reasonable when this function is called.  */)
   if (!WINDOW_LEAF_P (w))
     {
       /* Resize child windows vertically.  */
-      XSETINT (delta, r->total_lines - w->total_lines);
+      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);
+      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;
        }
@@ -2863,15 +3081,22 @@ window-start value is reasonable when this function is called.  */)
       if (!resize_failed)
        {
          w->left_col = r->left_col;
-         XSETINT (delta, r->total_cols - w->total_cols);
-         resize_root_window (window, delta, Qt, Qnil);
+         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;
            }
@@ -2980,27 +3205,47 @@ 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 (struct frame *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;
 
-  if (FRAME_TOP_MARGIN (frame) > 0)
-    min_height += FRAME_TOP_MARGIN (frame);
+      min_height += FRAME_TOP_MARGIN_HEIGHT (frame);
+      min_height += FRAME_INTERNAL_BORDER_WIDTH (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_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 (*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.
@@ -3010,31 +3255,37 @@ check_frame_size (struct frame *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)
-       w->left_margin_cols = w->right_margin_cols = margin_cols / 2;
+      int unit = WINDOW_FRAME_COLUMN_WIDTH (w);
+
+      margin_width = box_width - MIN_SAFE_WINDOW_PIXEL_WIDTH (w);
+
+      if (WINDOW_RIGHT_MARGIN_WIDTH (w) > 0)
+       {
+         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
-       w->right_margin_cols = margin_cols;
+       w->left_margin_cols = margin_width / unit;
+
+      return 1;
     }
-  else
-    w->left_margin_cols = margin_cols;
-  return 1;
 }
 \f
 /* The following three routines are needed for running a window's
@@ -3064,13 +3315,15 @@ select_frame_norecord (Lisp_Object frame)
 void
 run_window_configuration_change_hook (struct frame *f)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object frame, global_wcch
     = Fdefault_value (Qwindow_configuration_change_hook);
   XSETFRAME (frame, f);
 
-  if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code))
+  if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code)) {
+    dynwind_end ();
     return;
+  }
 
   /* Use the right buffer.  Matters when running the local hooks.  */
   if (current_buffer != XBUFFER (Fwindow_buffer (Qnil)))
@@ -3095,18 +3348,18 @@ run_window_configuration_change_hook (struct frame *f)
        if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook,
                                      buffer)))
          {
-           ptrdiff_t inner_count = SPECPDL_INDEX ();
+           dynwind_begin ();
            record_unwind_protect (select_window_norecord, selected_window);
            select_window_norecord (window);
            run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
                                           buffer));
-           unbind_to (inner_count, Qnil);
+           dynwind_end ();
          }
       }
   }
 
   run_funs (global_wcch);
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 DEFUN ("run-window-configuration-change-hook", Frun_window_configuration_change_hook,
@@ -3119,11 +3372,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,
@@ -3131,8 +3396,8 @@ 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->contents);
+  dynwind_begin ();
+  bool samebuf = EQ (buffer, w->contents);
 
   wset_buffer (w, buffer);
 
@@ -3171,16 +3436,13 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
     }
   /* 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 = 28;
+  wset_redisplay (w);
+  w->update_mode_line = true;
 
-  /* We must select BUFFER for running the window-scroll-functions.  */
-  /* We can't check ! NILP (Vwindow_scroll_functions) here
-     because that might itself be a local variable.  */
-  if (window_initialized)
-    {
-      record_unwind_current_buffer ();
-      Fset_buffer (buffer);
-    }
+  /* We must select BUFFER to run the window-scroll-functions and to look up
+     the buffer-local value of Vwindow_point_insertion_type.  */
+  record_unwind_current_buffer ();
+  Fset_buffer (buffer);
 
   XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
 
@@ -3202,14 +3464,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);
+  dynwind_end ();
 }
 
 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.
 
@@ -3344,7 +3607,7 @@ temp_output_buffer_show (register Lisp_Object buf)
       /* Run temp-buffer-show-hook, with the chosen window selected
         and its buffer current.  */
       {
-        ptrdiff_t count = SPECPDL_INDEX ();
+        dynwind_begin ();
         Lisp_Object prev_window, prev_buffer;
         prev_window = selected_window;
         XSETBUFFER (prev_buffer, old);
@@ -3358,7 +3621,7 @@ temp_output_buffer_show (register Lisp_Object buf)
         Fselect_window (window, Qt);
         Fset_buffer (w->contents);
         Frun_hooks (1, &Qtemp_buffer_show_hook);
-        unbind_to (count, Qnil);
+        dynwind_end ();
       }
     }
 }
@@ -3381,6 +3644,8 @@ make_parent_window (Lisp_Object window, bool horflag)
   adjust_window_count (p, 1);
   XSETWINDOW (parent, p);
 
+  p->sequence_number = ++sequence_number;
+
   replace_window (window, parent, 1);
 
   wset_next (o, Qnil);
@@ -3409,6 +3674,7 @@ make_window (void)
   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);
@@ -3426,6 +3692,7 @@ make_window (void)
   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;
 
@@ -3436,6 +3703,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_min = NILP (add) ? 0 : - XINT (w->new_pixel);
+  EMACS_INT size_max = size_min + min (INT_MAX, MOST_POSITIVE_FIXNUM);
+
+  CHECK_RANGED_INTEGER (size, size_min, 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.
@@ -3470,8 +3761,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',
@@ -3480,6 +3771,7 @@ 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 (WINDOW_VERTICAL_COMBINATION_P (w))
@@ -3491,26 +3783,33 @@ window_resize_check (struct window *w, bool horflag)
        {
          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 remaining_pixels = XINT (w->new_pixel);
+
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
-             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+
+             remaining_pixels -= XINT (c->new_pixel);
+             if (remaining_pixels < 0)
+               return 0;
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
-         return (sum_of_sizes == XINT (w->new_total));
+
+         return remaining_pixels == 0;
        }
     }
   else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
@@ -3521,26 +3820,33 @@ window_resize_check (struct window *w, bool horflag)
        /* The sum of the widths of the child windows of W must equal W's
           width.  */
        {
-         int sum_of_sizes = 0;
+         int remaining_pixels = XINT (w->new_pixel);
+
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
-             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+
+             remaining_pixels -= XINT (c->new_pixel);
+             if (remaining_pixels < 0)
+               return 0;
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
-         return (sum_of_sizes == XINT (w->new_total));
+
+         return remaining_pixels == 0;
        }
       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;
        }
     }
@@ -3548,12 +3854,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
@@ -3562,25 +3871,30 @@ 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)
     {
-      w->total_cols = XFASTINT (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 = w->left_col;
+      edge = w->pixel_left;
     }
   else
     {
-      w->total_lines = XFASTINT (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 = w->top_line;
+      edge = w->pixel_top;
     }
 
   if (WINDOW_VERTICAL_COMBINATION_P (w))
@@ -3590,12 +3904,19 @@ window_resize_apply (struct window *w, bool horflag)
       while (c)
        {
          if (horflag)
-           c->left_col = pos;
+           {
+             c->pixel_left = edge;
+             c->left_col = edge / unit;
+           }
          else
-           c->top_line = pos;
+           {
+             c->pixel_top = edge;
+             c->top_line = edge / unit;
+           }
          window_resize_apply (c, horflag);
          if (!horflag)
-           pos = pos + c->total_lines;
+           edge = edge + c->pixel_height;
+
          c = NILP (c->next) ? 0 : XWINDOW (c->next);
        }
     }
@@ -3606,18 +3927,93 @@ window_resize_apply (struct window *w, bool horflag)
       while (c)
        {
          if (horflag)
-           c->left_col = pos;
+           {
+             c->pixel_left = edge;
+             c->left_col = edge / unit;
+           }
          else
-           c->top_line = pos;
+           {
+             c->pixel_top = edge;
+             c->top_line = edge / unit;
+           }
+
          window_resize_apply (c, horflag);
          if (horflag)
-           pos = pos + c->total_cols;
+           edge = edge + c->pixel_width;
+
          c = NILP (c->next) ? 0 : XWINDOW (c->next);
        }
     }
+  else
+    {
+      adjust_window_margins (w);
+      /* Bug#15957.  */
+      w->window_end_valid = 0;
+    }
 }
 
 
+/* 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.
@@ -3639,20 +4035,58 @@ be applied on the Elisp level.  */)
   bool horflag = !NILP (horizontal);
 
   if (!window_resize_check (r, horflag)
-      || (XINT (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 = 30;
+  fset_redisplay (f);
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
   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));
+  /* Handle the mini window.  */
+  if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+    {
+      struct window *m = XWINDOW (f->minibuffer_window);
+
+      if (NILP (horizontal))
+       {
+         m->top_line = r->top_line + r->total_lines;
+         m->total_lines = XFASTINT (m->new_total);
+       }
+      else
+       m->total_cols = XFASTINT (m->new_total);
+    }
+
+  unblock_input ();
 
   return Qt;
 }
@@ -3660,59 +4094,113 @@ 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)));
+  int new_size, new_pixel_size;
+  int unit = horflag ? FRAME_COLUMN_WIDTH (f) : FRAME_LINE_HEIGHT (f);
+
+  /* Don't let the size drop below one unit.  This is more comforting
+     when we are called from x_set_tool_bar_lines since the latter may
+     have implicitly given us a zero or negative height.  */
+  if (pixelwise)
+    {
+      /* Note: This does not include the size for internal borders
+        since these are not part of the frame's text area.  */
+      new_pixel_size = max (horflag
+                           ? size
+                           : (size
+                              - FRAME_TOP_MARGIN_HEIGHT (f)
+                              - ((FRAME_HAS_MINIBUF_P (f)
+                                  && !FRAME_MINIBUF_ONLY_P (f))
+                                 ? FRAME_LINE_HEIGHT (f) : 0)),
+                           unit);
+      new_size = new_pixel_size / unit;
+    }
+  else
+    {
+      new_size = max (horflag
+                     ? size
+                     : (size
+                        - FRAME_TOP_MARGIN (f)
+                        - ((FRAME_HAS_MINIBUF_P (f)
+                            && !FRAME_MINIBUF_ONLY_P (f))
+                           ? 1 : 0)),
+                     1);
+      new_pixel_size = new_size * unit;
+    }
 
   r->top_line = FRAME_TOP_MARGIN (f);
-  if (WINDOW_LEAF_P (r))
+  r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
+
+  if (new_pixel_size == old_pixel_size)
+    ;
+  else if (WINDOW_LEAF_P (r))
     /* For a leaf root window just set the size.  */
     if (horflag)
-      r->total_cols = new_size;
+      {
+       r->total_cols = new_size;
+       r->pixel_width = new_pixel_size;
+      }
     else
-      r->total_lines = 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 = 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);
+               }
+#if 0 /* Let's try without killing other windows.  */
              else
                {
                  /* We lost.  Delete all windows but the frame's
@@ -3720,10 +4208,17 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
                  root = f->selected_window;
                  Fdelete_other_windows_internal (root, Qnil);
                  if (horflag)
-                   XWINDOW (root)->total_cols = new_size;
+                   {
+                     XWINDOW (root)->total_cols = new_size;
+                     XWINDOW (root)->pixel_width = new_pixel_size;
+                   }
                  else
-                   XWINDOW (root)->total_lines = new_size;
+                   {
+                     XWINDOW (root)->total_lines = new_size;
+                     XWINDOW (root)->pixel_height = new_pixel_size;
+                   }
                }
+#endif /* 0 */
            }
        }
     }
@@ -3732,42 +4227,47 @@ resize_frame_windows (struct frame *f, int size, bool horflag)
     {
       m = XWINDOW (mini);
       if (horflag)
-       m->total_cols = size;
+       {
+         m->total_cols = size;
+         m->pixel_width = new_pixel_size;
+       }
       else
        {
          /* Are we sure we always want 1 line here?  */
          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 = 31;
+  fset_redisplay (f);
 }
 
 
 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
@@ -3776,19 +4276,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
@@ -3812,7 +4317,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
@@ -3820,26 +4325,25 @@ 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 ((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, make_number
-                       (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)
-              != (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");
     }
 
-  /* This is our point of no return. */
+  /* This is our point of no return.  */
   if (combination_limit)
     {
       /* Save the old value of o->normal_cols/lines.  It gets corrupted
@@ -3855,14 +4359,16 @@ 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, make_number
-                     (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 = 32;
+  fset_redisplay (f);
   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
   new = make_window ();
   n = XWINDOW (new);
@@ -3903,18 +4409,33 @@ set correctly.  See the code of `split-window' for how this is done.  */)
   /* Directly assign orthogonal coordinates and sizes.  */
   if (horflag)
     {
+      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
     {
+      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 ();
@@ -3993,15 +4514,14 @@ Signal an error when WINDOW is the only window on its frame.  */)
     }
 
   if (window_resize_check (r, horflag)
-      && (XINT (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))
@@ -4012,7 +4532,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
            hlinfo->mouse_face_window = Qnil;
        }
 
-      windows_or_buffers_changed = 33;
+      fset_redisplay (f);
       Vwindow_list = Qnil;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
@@ -4112,54 +4632,78 @@ 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.  */
-      w->top_line = r->top_line + r->total_lines;
-      w->total_lines -= XINT (value);
-      /* Enforce full redisplay.  FIXME: make it more selective.  */
-      windows_or_buffers_changed = 34;
-      adjust_frame_glyphs (f);
-      unblock_input ();
+         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);
+           }
+
+         /* Grow the mini-window.  */
+         w->pixel_top = r->pixel_top + r->pixel_height;
+         w->top_line = r->top_line + r->total_lines;
+         /* Make sure the mini-window has always at least one line.  */
+         w->pixel_height = max (w->pixel_height + pixel_height,
+                                FRAME_LINE_HEIGHT (f));
+         w->total_lines = max (w->total_lines + line_height, 1);
+
+         /* 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 = 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);
@@ -4167,8 +4711,11 @@ shrink_mini_window (struct window *w)
          /* Shrink the mini-window.  */
          w->top_line = r->top_line + r->total_lines;
          w->total_lines = 1;
-         /* Enforce full redisplay.  FIXME: make it more selective.  */
-         windows_or_buffers_changed = 35;
+         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 ();
        }
@@ -4197,26 +4744,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 = r->total_lines + 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);
 
       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 = 36;
+      fset_redisplay (f);
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
       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
@@ -4279,6 +4827,8 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror)
   immediate_quit = 1;
   n = clip_to_bounds (INT_MIN, n, INT_MAX);
 
+  wset_redisplay (XWINDOW (window));
+
   /* If we must, use the pixel-based version which is much slower than
      the line-based one but can handle varying line heights.  */
   if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
@@ -4286,6 +4836,8 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror)
   else
     window_scroll_line_based (window, n, whole, noerror);
 
+  /* Bug#15957.  */
+  XWINDOW (window)->window_end_valid = 0;
   immediate_quit = 0;
 }
 
@@ -4318,7 +4870,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
   /* If PT is not visible in WINDOW, move back one half of
      the screen.  Allow PT to be partially visible, otherwise
      something like (scroll-down 1) with PT in the line before
-     the partially visible one would recenter. */
+     the partially visible one would recenter.  */
 
   if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
     {
@@ -4347,7 +4899,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
     }
   else if (auto_window_vscroll_p)
     {
-      if (rtop || rbot)                /* partially visible */
+      if (rtop || rbot)                /* Partially visible.  */
        {
          int px;
          int dy = frame_line_height;
@@ -4818,7 +5370,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror)
 static void
 scroll_command (Lisp_Object n, int direction)
 {
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   eassert (eabs (direction) == 1);
 
@@ -4828,9 +5380,6 @@ scroll_command (Lisp_Object n, int direction)
     {
       record_unwind_protect (save_excursion_restore, save_excursion_save ());
       Fset_buffer (XWINDOW (selected_window)->contents);
-
-      /* Make redisplay consider other windows than just selected_window.  */
-      windows_or_buffers_changed = 37;
     }
 
   if (NILP (n))
@@ -4843,7 +5392,7 @@ scroll_command (Lisp_Object n, int direction)
       window_scroll (selected_window, XINT (n) * direction, 0, 0);
     }
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "^P",
@@ -4886,8 +5435,10 @@ specifies the window.  This takes precedence over
   if (MINI_WINDOW_P (XWINDOW (selected_window))
       && !NILP (Vminibuf_scroll_window))
     window = Vminibuf_scroll_window;
-  /* If buffer is specified, scroll that buffer.  */
-  else if (!NILP (Vother_window_scroll_buffer))
+  /* If buffer is specified and live, scroll that buffer.  */
+  else if (!NILP (Vother_window_scroll_buffer)
+          && BUFFERP (Vother_window_scroll_buffer)
+          && BUFFER_LIVE_P (XBUFFER (Vother_window_scroll_buffer)))
     {
       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
       if (NILP (window))
@@ -4933,14 +5484,13 @@ specifies the window to scroll.  This takes precedence over
 {
   Lisp_Object window;
   struct window *w;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   window = Fother_window_for_scrolling ();
   w = XWINDOW (window);
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
-  windows_or_buffers_changed = 38;
 
   Fset_buffer (w->contents);
   SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm));
@@ -4958,7 +5508,7 @@ specifies the window to scroll.  This takes precedence over
     }
 
   set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   return Qnil;
 }
@@ -4976,7 +5526,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);
 
@@ -4999,7 +5549,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);
 
@@ -5096,14 +5646,16 @@ and redisplay normally--don't erase and redraw the frame.  */)
 {
   struct window *w = XWINDOW (selected_window);
   struct buffer *buf = XBUFFER (w->contents);
-  struct buffer *obuf = current_buffer;
   bool center_p = 0;
   ptrdiff_t charpos, bytepos;
   EMACS_INT iarg IF_LINT (= 0);
   int this_scroll_margin;
 
+  if (buf != current_buffer)
+    error ("`recenter'ing a window that does not display current-buffer.");
+  
   /* If redisplay is suppressed due to an error, try again.  */
-  obuf->display_error_modiff = 0;
+  buf->display_error_modiff = 0;
 
   if (NILP (arg))
     {
@@ -5125,7 +5677,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
       center_p = 1;
     }
-  else if (CONSP (arg)) /* Just C-u. */
+  else if (CONSP (arg)) /* Just C-u.  */
     center_p = 1;
   else
     {
@@ -5134,12 +5686,10 @@ and redisplay normally--don't erase and redraw the frame.  */)
       iarg = XINT (arg);
     }
 
-  set_buffer_internal (buf);
-
   /* Do this after making BUF current
      in case scroll_margin is buffer-local.  */
-  this_scroll_margin =
-    max (0, min (scroll_margin, w->total_lines / 4));
+  this_scroll_margin
+    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
@@ -5187,7 +5737,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
            h -= it.current_y;
          else
            {
-             /* Last line has no newline */
+             /* Last line has no newline */
              h -= line_bottom_y (&it);
              it.vpos++;
            }
@@ -5266,29 +5816,42 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
   w->optional_new_start = 1;
 
-  w->start_at_line_beg = (bytepos == BEGV_BYTE ||
-                         FETCH_BYTE (bytepos - 1) == '\n');
+  w->start_at_line_beg = (bytepos == BEGV_BYTE
+                         || FETCH_BYTE (bytepos - 1) == '\n');
 
-  set_buffer_internal (obuf);
   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",
@@ -5381,17 +5944,24 @@ struct save_window_data
 
     /* All fields above are traced by the GC.
        From `frame-cols' down, the fields are ignored by the GC.  */
-
-    int frame_cols, frame_lines, frame_menu_bar_lines;
-    int frame_tool_bar_lines;
+    /* 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  */
+/* This is saved as a Lisp_Vector.  */
 struct saved_window
 {
   struct vectorlike_header header;
 
-  Lisp_Object window, buffer, start, pointm, mark;
+  Lisp_Object window, buffer, start, pointm;
+  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;
@@ -5428,6 +5998,13 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config
   return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
 }
 
+/* From Chong's unwind_create_frame_1.  */
+static void
+unwind_change_frame (Lisp_Object val)
+{
+  inhibit_lisp_code = val;
+}
+
 DEFUN ("set-window-configuration", Fset_window_configuration,
        Sset_window_configuration, 1, 1, 0,
        doc: /* Set the configuration of windows and buffers as specified by CONFIGURATION.
@@ -5507,13 +6084,17 @@ the return value is nil.  Otherwise the value is t.  */)
       int n_leaf_windows;
       ptrdiff_t k;
       int i, n;
-
+      ptrdiff_t count = SPECPDL_INDEX ();
       /* If the frame has been resized since this window configuration was
         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);
 
@@ -5532,17 +6113,20 @@ the return value is nil.  Otherwise the value is t.  */)
            call1 (Qrecord_window_buffer, window);
        }
 
+      /* Don't run lisp in the following segment since the frame is in a
+        completely inconsistent state.  See Bug#16207.  */
+      record_unwind_protect (unwind_change_frame, inhibit_lisp_code);
+      inhibit_lisp_code = Qt;
       /* The mouse highlighting code could get screwed up
         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);
-#ifdef HAVE_MENUS
-      if (data->frame_menu_bar_lines
-         != previous_frame_menu_bar_lines)
+      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 (FRAME_WINDOW_P (f))
@@ -5553,10 +6137,8 @@ the return value is nil.  Otherwise the value is t.  */)
            set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
                                make_number (0));
        }
-#endif
 #ifdef HAVE_WINDOW_SYSTEM
-      if (data->frame_tool_bar_lines
-         != previous_frame_tool_bar_lines)
+      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
@@ -5575,7 +6157,7 @@ the return value is nil.  Otherwise the value is t.  */)
                           BUF_PT_BYTE (XBUFFER (w->contents)));
        }
 
-      windows_or_buffers_changed = 39;
+      fset_redisplay (f);
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
       /* Problem: Freeing all matrices and later allocating them again
@@ -5628,6 +6210,10 @@ the return value is nil.  Otherwise the value is t.  */)
          /* 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);
@@ -5676,8 +6262,6 @@ the return value is nil.  Otherwise the value is t.  */)
              set_marker_restricted (w->start, p->start, w->contents);
              set_marker_restricted (w->pointm, p->pointm,
                                     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
@@ -5731,9 +6315,13 @@ the return value is nil.  Otherwise the value is t.  */)
       /* 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)->contents), last_selected_window)
+        that window's old buffer.
+
+        Do not record the buffer here.  We do that in a separate call
+        to select_window below.  See also Bug#16207.  */
+      select_window (data->current_window, Qt, 1);
+      BVAR (XBUFFER (XWINDOW (selected_window)->contents),
+           last_selected_window)
        = selected_window;
 
       if (NILP (data->focus_frame)
@@ -5741,12 +6329,12 @@ the return value is nil.  Otherwise the value is t.  */)
              && 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);
-#ifdef HAVE_MENUS
+      /* 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))
        {
 #ifdef HAVE_WINDOW_SYSTEM
@@ -5759,7 +6347,6 @@ the return value is nil.  Otherwise the value is t.  */)
            set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
                                make_number (0));
        }
-#endif
 #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),
@@ -5777,6 +6364,7 @@ the return value is nil.  Otherwise the value is t.  */)
 
       adjust_frame_glyphs (f);
       unblock_input ();
+      unbind_to (count, Qnil);
 
       /* Scan dead buffer windows.  */
       for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
@@ -5786,6 +6374,10 @@ the return value is nil.  Otherwise the value is t.  */)
            delete_deletable_window (window);
        }
 
+      /* Record the selected window's buffer here.  The window should
+        already be the selected one from the call above.  */
+      select_window (data->current_window, Qnil, 0);
+
       /* 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
@@ -5938,6 +6530,10 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
       wset_temslot (w, make_number (i)); i++;
       p->window = window;
       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);
@@ -6016,31 +6612,21 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
          XMARKER (p->pointm)->insertion_type
-           = !NILP (Vwindow_point_insertion_type);
+           = !NILP (buffer_local_value /* Don't signal error if void.  */
+                    (Qwindow_point_insertion_type, w->contents));
 
          p->start = Fcopy_marker (w->start, Qnil);
          p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil;
-
-         tem = BVAR (XBUFFER (w->contents), mark);
-         p->mark = Fcopy_marker (tem, Qnil);
        }
       else
        {
          p->pointm = Qnil;
          p->start = Qnil;
-         p->mark = Qnil;
          p->start_at_line_beg = Qnil;
        }
 
-      if (NILP (w->parent))
-       p->parent = Qnil;
-      else
-       p->parent = XWINDOW (w->parent)->temslot;
-
-      if (NILP (w->prev))
-       p->prev = Qnil;
-      else
-       p->prev = XWINDOW (w->prev)->temslot;
+      p->parent = NILP (w->parent) ? Qnil : XWINDOW (w->parent)->temslot;
+      p->prev = NILP (w->prev) ? Qnil : XWINDOW (w->prev)->temslot;
 
       if (WINDOWP (w->contents))
        i = save_window_save (w->contents, vector, i);
@@ -6054,8 +6640,8 @@ DEFUN ("current-window-configuration", Fcurrent_window_configuration,
        doc: /* Return an object representing the current window configuration of FRAME.
 If FRAME is nil or omitted, use the selected frame.
 This describes the number of windows, their sizes and current buffers,
-and for each displayed buffer, where display starts, and the positions of
-point and mark.  An exception is made for point in the current buffer:
+and for each displayed buffer, where display starts, and the position of
+point.  An exception is made for point in the current buffer:
 its value is -not- saved.
 This also records the currently selected frame, and FRAME's focus
 redirection (see `redirect-frame-focus').  The variable
@@ -6077,6 +6663,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);
@@ -6103,7 +6693,8 @@ apply_window_adjustment (struct window *w)
   adjust_window_margins (w);
   clear_glyph_matrix (w->current_matrix);
   w->window_end_valid = 0;
-  windows_or_buffers_changed = 40;
+  windows_or_buffers_changed = 30;
+  wset_redisplay (w);
   adjust_frame_glyphs (XFRAME (WINDOW_FRAME (w)));
 }
 
@@ -6163,8 +6754,10 @@ as nil.  */)
   (Lisp_Object window)
 {
   struct window *w = decode_live_window (window);
-  return Fcons (w->left_margin_cols ? make_number (w->left_margin_cols) : Qnil,
-               w->right_margin_cols ? make_number (w->right_margin_cols) : Qnil);
+  return Fcons (w->left_margin_cols
+               ? make_number (w->left_margin_cols) : Qnil,
+               w->right_margin_cols
+               ? make_number (w->right_margin_cols) : Qnil);
 }
 
 
@@ -6274,15 +6867,14 @@ DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars,
        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.
+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 t if scroll bars was actually changed and nil otherwise.  */)
+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)
 {
@@ -6305,9 +6897,7 @@ value.  */)
 {
   struct window *w = decode_live_window (window);
 
-  return list4 (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
-                             ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
-                             : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
+  return list4 (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (w)),
                make_number (WINDOW_SCROLL_BAR_COLS (w)),
                w->vertical_scroll_bar_type, Qnil);
 }
@@ -6477,6 +7067,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)
@@ -6491,8 +7085,7 @@ compare_window_configurations (Lisp_Object configuration1,
                  || !EQ (sw1->min_hscroll, sw2->min_hscroll)
                  || !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg)
                  || NILP (Fequal (sw1->start, sw2->start))
-                 || NILP (Fequal (sw1->pointm, sw2->pointm))
-                 || NILP (Fequal (sw1->mark, sw2->mark))))
+                 || NILP (Fequal (sw1->pointm, sw2->pointm))))
          || !EQ (sw1->left_margin_cols, sw2->left_margin_cols)
          || !EQ (sw1->right_margin_cols, sw2->right_margin_cols)
          || !EQ (sw1->left_fringe_width, sw2->left_fringe_width)
@@ -6509,7 +7102,7 @@ compare_window_configurations (Lisp_Object configuration1,
 DEFUN ("compare-window-configurations", Fcompare_window_configurations,
        Scompare_window_configurations, 2, 2, 0,
        doc: /* Compare two window configurations as regards the structure of windows.
-This function ignores details such as the values of point and mark
+This function ignores details such as the values of point
 and scrolling positions.  */)
   (Lisp_Object x, Lisp_Object y)
 {
@@ -6526,8 +7119,6 @@ init_window_once (void)
   Vterminal_frame = selected_frame;
   minibuf_window = f->minibuffer_window;
   selected_window = f->selected_window;
-
-  window_initialized = 1;
 }
 
 void
@@ -6539,6 +7130,8 @@ init_window (void)
 void
 syms_of_window (void)
 {
+#include "window.x"
+
   DEFSYM (Qscroll_up, "scroll-up");
   DEFSYM (Qscroll_down, "scroll-down");
   DEFSYM (Qscroll_command, "scroll-command");
@@ -6555,6 +7148,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");
@@ -6565,6 +7159,8 @@ syms_of_window (void)
   DEFSYM (Qabove, "above");
   DEFSYM (Qbelow, "below");
   DEFSYM (Qclone_of, "clone-of");
+  DEFSYM (Qfloor, "floor");
+  DEFSYM (Qceiling, "ceiling");
 
   staticpro (&Vwindow_list);
 
@@ -6595,7 +7191,7 @@ is displayed in the `mode-line' face.  */);
   mode_line_in_non_selected_windows = 1;
 
   DEFVAR_LISP ("other-window-scroll-buffer", Vother_window_scroll_buffer,
-              doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.  */);
+              doc: /* If this is a live buffer, \\[scroll-other-window] should scroll its window.  */);
   Vother_window_scroll_buffer = Qnil;
 
   DEFVAR_BOOL ("auto-window-vscroll", auto_window_vscroll_p,
@@ -6622,6 +7218,7 @@ on their symbols to be controlled by this variable.  */);
   DEFVAR_LISP ("window-point-insertion-type", Vwindow_point_insertion_type,
               doc: /* Type of marker to use for `window-point'.  */);
   Vwindow_point_insertion_type = Qnil;
+  DEFSYM (Qwindow_point_insertion_type, "window_point_insertion_type");
 
   DEFVAR_LISP ("window-configuration-change-hook",
               Vwindow_configuration_change_hook,
@@ -6713,104 +7310,16 @@ Parameters not saved by `current-window-configuration' or
 respectively are not installed by `window-state-put'.  */);
   Vwindow_persistent_parameters = list1 (Fcons (Qclone_of, Qt));
 
-  defsubr (&Sselected_window);
-  defsubr (&Sminibuffer_window);
-  defsubr (&Swindow_minibuffer_p);
-  defsubr (&Swindowp);
-  defsubr (&Swindow_valid_p);
-  defsubr (&Swindow_live_p);
-  defsubr (&Swindow_frame);
-  defsubr (&Sframe_root_window);
-  defsubr (&Sframe_first_window);
-  defsubr (&Sframe_selected_window);
-  defsubr (&Sset_frame_selected_window);
-  defsubr (&Spos_visible_in_window_p);
-  defsubr (&Swindow_line_height);
-  defsubr (&Swindow_buffer);
-  defsubr (&Swindow_parent);
-  defsubr (&Swindow_top_child);
-  defsubr (&Swindow_left_child);
-  defsubr (&Swindow_next_sibling);
-  defsubr (&Swindow_prev_sibling);
-  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_total_width);
-  defsubr (&Swindow_normal_size);
-  defsubr (&Swindow_new_total);
-  defsubr (&Swindow_new_normal);
-  defsubr (&Sset_window_new_total);
-  defsubr (&Sset_window_new_normal);
-  defsubr (&Swindow_resize_apply);
-  defsubr (&Swindow_body_height);
-  defsubr (&Swindow_body_width);
-  defsubr (&Swindow_hscroll);
-  defsubr (&Sset_window_hscroll);
-  defsubr (&Swindow_redisplay_end_trigger);
-  defsubr (&Sset_window_redisplay_end_trigger);
-  defsubr (&Swindow_edges);
-  defsubr (&Swindow_pixel_edges);
-  defsubr (&Swindow_absolute_pixel_edges);
-  defsubr (&Swindow_inside_edges);
-  defsubr (&Swindow_inside_pixel_edges);
-  defsubr (&Swindow_inside_absolute_pixel_edges);
-  defsubr (&Scoordinates_in_window_p);
-  defsubr (&Swindow_at);
-  defsubr (&Swindow_point);
-  defsubr (&Swindow_start);
-  defsubr (&Swindow_end);
-  defsubr (&Sset_window_point);
-  defsubr (&Sset_window_start);
-  defsubr (&Swindow_dedicated_p);
-  defsubr (&Sset_window_dedicated_p);
-  defsubr (&Swindow_display_table);
-  defsubr (&Sset_window_display_table);
-  defsubr (&Snext_window);
-  defsubr (&Sprevious_window);
-  defsubr (&Sget_buffer_window);
-  defsubr (&Sdelete_other_windows_internal);
-  defsubr (&Sdelete_window_internal);
-  defsubr (&Sresize_mini_window_internal);
-  defsubr (&Sset_window_buffer);
-  defsubr (&Srun_window_configuration_change_hook);
-  defsubr (&Sselect_window);
-  defsubr (&Sforce_window_update);
-  defsubr (&Ssplit_window_internal);
-  defsubr (&Sscroll_up);
-  defsubr (&Sscroll_down);
-  defsubr (&Sscroll_left);
-  defsubr (&Sscroll_right);
-  defsubr (&Sother_window_for_scrolling);
-  defsubr (&Sscroll_other_window);
-  defsubr (&Sminibuffer_selected_window);
-  defsubr (&Srecenter);
-  defsubr (&Swindow_text_height);
-  defsubr (&Smove_to_window_line);
-  defsubr (&Swindow_configuration_p);
-  defsubr (&Swindow_configuration_frame);
-  defsubr (&Sset_window_configuration);
-  defsubr (&Scurrent_window_configuration);
-  defsubr (&Sset_window_margins);
-  defsubr (&Swindow_margins);
-  defsubr (&Sset_window_fringes);
-  defsubr (&Swindow_fringes);
-  defsubr (&Sset_window_scroll_bars);
-  defsubr (&Swindow_scroll_bars);
-  defsubr (&Swindow_vscroll);
-  defsubr (&Sset_window_vscroll);
-  defsubr (&Scompare_window_configurations);
-  defsubr (&Swindow_list);
-  defsubr (&Swindow_list_1);
-  defsubr (&Swindow_prev_buffers);
-  defsubr (&Sset_window_prev_buffers);
-  defsubr (&Swindow_next_buffers);
-  defsubr (&Sset_window_next_buffers);
-  defsubr (&Swindow_parameters);
-  defsubr (&Swindow_parameter);
-  defsubr (&Sset_window_parameter);
+  DEFVAR_BOOL ("window-resize-pixelwise", window_resize_pixelwise,
+              doc: /*  Non-nil means resize windows pixelwise.
+This currently affects the functions: `split-window', `maximize-window',
+`minimize-window', `fit-window-to-buffer' and `fit-frame-to-buffer', and
+all functions that symmetrically resize 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;
 }
 
 void