Fixes: debbugs:17865
[bpt/emacs.git] / src / window.c
index d1f3dd5..8e8252d 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.
@@ -54,6 +54,8 @@ static Lisp_Object Qwindow_resize_root_window, Qwindow_resize_root_window_vertic
 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 *);
@@ -123,7 +125,7 @@ static int window_initialized;
 /* 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;
 
@@ -558,7 +560,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.
 
@@ -566,8 +568,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);
@@ -682,7 +693,7 @@ selected one.  */)
 }
 \f
 DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width, 0, 1, 0,
-       doc: /* Return the pixel width of window WINDOW.
+       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 fringes and margins of WINDOW as well as
@@ -695,45 +706,88 @@ spanned by its children.  */)
 }
 
 DEFUN ("window-pixel-height", Fwindow_pixel_height, Swindow_pixel_height, 0, 1, 0,
-       doc: /* Return the pixel height of window WINDOW.
+       doc: /* Return the height 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, its pixel height is the height of the
-screen areas spanned by its children.  */)
+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)->pixel_height);
 }
 
-DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 1, 0,
-       doc: /* Return the total height, in lines, of window WINDOW.
+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 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 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 height is reported as an
-integer multiple of the default character height.  */)
-  (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)
 {
-  return make_number (decode_valid_window (window)->total_lines);
+  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, 1, 0,
-       doc: /* Return the total width, in columns, of window WINDOW.
+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 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.
-
-On a graphical display, this total width is reported as an
-integer multiple of the default character width.  */)
-  (Lisp_Object window)
+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,
@@ -811,62 +865,66 @@ 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_height (struct window *w, bool pixelwise)
 {
-  int pixels = (w->pixel_height
-               - WINDOW_BOTTOM_DIVIDER_WIDTH (w)
+  int height = (w->pixel_height
                - WINDOW_HEADER_LINE_HEIGHT (w)
-               - WINDOW_MODE_LINE_HEIGHT (w));
-  int unit = FRAME_LINE_HEIGHT (WINDOW_XFRAME (w));
+               - WINDOW_MODE_LINE_HEIGHT (w)
+               - WINDOW_BOTTOM_DIVIDER_WIDTH (w));
 
-  return pixelwise ? pixels : ((pixels + unit - 1) / unit);
+  /* 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_width (struct window *w, bool pixelwise)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
 
-  int pixels = (w->pixel_width
-               - WINDOW_RIGHT_DIVIDER_WIDTH (w)
-               - (WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
-                  ? WINDOW_SCROLL_BAR_AREA_WIDTH (w)
-                  : ((!FRAME_WINDOW_P (f)
-                      && !WINDOW_RIGHTMOST_P (w)
-                      && !WINDOW_RIGHT_DIVIDER_WIDTH (w)
-                      && !WINDOW_FULL_WIDTH_P (w))
-                     /* According to Eli this is either 1 or 0.  */
-                     ? 1 : 0))
+  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));
-  int unit = FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w));
 
-  return pixelwise ? pixels : ((pixels + unit - 1) / unit);
+  /* 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, in lines, 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 in pixels.
-
-The returned height does not include the mode line or header line.  On a
-graphical display, the height is expressed as an integer multiple of the
-default character height if PIXELWISE is nil.
-
-If PIXELWISE is nil and a line at the bottom of the text area is only
-partially visible, that counts as a whole line; to exclude
-partially-visible lines, use `window-text-height'.  */)
+       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),
@@ -874,19 +932,16 @@ partially-visible lines, use `window-text-height'.  */)
 }
 
 DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 2, 0,
-       doc: /* Return the width, in columns, of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one.
-
-Optional argument PIXELWISE non-nil means return the width in pixels.
-
-The return value does not include any vertical dividers, fringe or
-marginal areas, or scroll bars.  On a graphical display, the width is
-expressed as an integer multiple of the default character width if
-PIXELWISE is nil.
-
-If PIXELWISE is nil and a column at the right of the text area is only
-partially visible, that counts as a whole column; to exclude
-partially-visible columns, use `window-text-width'.  */)
+       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),
@@ -895,7 +950,7 @@ partially-visible columns, use `window-text-width'.  */)
 
 DEFUN ("window-mode-line-height", Fwindow_mode_line_height,
        Swindow_mode_line_height, 0, 1, 0,
-       doc: /* Return the height in pixel of WINDOW's mode-line.
+       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)
 {
@@ -904,7 +959,7 @@ WINDOW must be a live window and defaults to the selected one.  */)
 
 DEFUN ("window-header-line-height", Fwindow_header_line_height,
        Swindow_header_line_height, 0, 1, 0,
-       doc: /* Return the height in pixel of WINDOW's header-line.
+       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)
 {
@@ -913,7 +968,7 @@ WINDOW must be a live window and defaults to the selected one.  */)
 
 DEFUN ("window-right-divider-width", Fwindow_right_divider_width,
        Swindow_right_divider_width, 0, 1, 0,
-       doc: /* Return the width of WINDOW's right divider.
+       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)
 {
@@ -922,13 +977,22 @@ 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 of WINDOW's bottom divider.
+       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))));
 }
 
+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_SCROLL_BAR_AREA_WIDTH (decode_live_window (window))));
+}
+
 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
        doc: /* Return the number of columns by which WINDOW is scrolled from left margin.
 WINDOW must be a live window and defaults to the selected one.  */)
@@ -1212,18 +1276,18 @@ 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 vertical window divider (which prevails horizontal
-     dividers)?  */
-  if (!WINDOW_RIGHTMOST_P (w)
-      && WINDOW_RIGHT_DIVIDER_WIDTH (w)
-      && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w)
-      && x <= right_x)
-    return ON_RIGHT_DIVIDER;
-  /* On the horizontal window divider?  */
-  else if (WINDOW_BOTTOM_DIVIDER_WIDTH (w)
-          && y >= (bottom_y - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
-          && y <= bottom_y)
+  /* 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
@@ -1240,12 +1304,13 @@ coordinates_in_window (register struct window *w, int x, int y)
         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;
@@ -1277,6 +1342,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))
@@ -1285,6 +1351,7 @@ 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?  */
@@ -1298,8 +1365,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)
@@ -1309,8 +1376,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 */
@@ -1329,6 +1396,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;
 
@@ -1365,8 +1434,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,
@@ -3155,6 +3226,7 @@ check_frame_size (struct frame *frame, int *width, int *height, bool pixelwise)
        min_height = 2 * min_height;
 
       min_height += FRAME_TOP_MARGIN_HEIGHT (frame);
+      min_height += FRAME_INTERNAL_BORDER_WIDTH (frame);
 
       if (*height < min_height)
        *height = min_height;
@@ -3365,6 +3437,7 @@ 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.  */
   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
@@ -3876,8 +3949,11 @@ window_resize_apply (struct window *w, bool horflag)
        }
     }
   else
-    /* Bug#15957.  */
-    w->window_end_valid = 0;
+    {
+      adjust_window_margins (w);
+      /* Bug#15957.  */
+      w->window_end_valid = 0;
+    }
 }
 
 
@@ -4000,6 +4076,20 @@ values.  */)
   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;
@@ -4025,38 +4115,43 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
   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, 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)
     {
-      new_pixel_size
-       = (horflag
-          ? size
-          : (size
-             - FRAME_TOP_MARGIN_HEIGHT (f)
-             - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
-                ? FRAME_LINE_HEIGHT (f) : 0)));
-      new_size = new_pixel_size / (horflag
-                                  ? FRAME_COLUMN_WIDTH (f)
-                                  : FRAME_LINE_HEIGHT (f));
+      /* 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= (horflag
-                ? size
-                : (size
-                   - FRAME_TOP_MARGIN (f)
-                   - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
-                      ? 1 : 0)));
-      new_pixel_size = new_size * (horflag
-                                  ? FRAME_COLUMN_WIDTH (f)
-                                  : FRAME_LINE_HEIGHT (f));
+      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);
   r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
 
   if (new_pixel_size == old_pixel_size)
-    return;
+    ;
   else if (WINDOW_LEAF_P (r))
     /* For a leaf root window just set the size.  */
     if (horflag)
@@ -4109,6 +4204,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
                  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
@@ -4126,6 +4222,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
                      XWINDOW (root)->pixel_height = new_pixel_size;
                    }
                }
+#endif /* 0 */
            }
        }
     }
@@ -4576,8 +4673,10 @@ grow_mini_window (struct window *w, int delta, bool pixelwise)
          /* Grow the mini-window.  */
          w->pixel_top = r->pixel_top + r->pixel_height;
          w->top_line = r->top_line + r->total_lines;
-         w->pixel_height += pixel_height;
-         w->total_lines += line_height;
+         /* 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?  */
@@ -5340,8 +5439,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))
@@ -5902,6 +6003,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.
@@ -5981,7 +6089,7 @@ 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
@@ -6010,6 +6118,10 @@ 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 ();
@@ -6207,6 +6319,18 @@ the return value is nil.  Otherwise the value is t.  */)
                               make_number (old_point),
                               XWINDOW (data->current_window)->contents);
 
+      /* 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.
+
+        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)
          || (FRAMEP (data->focus_frame)
              && FRAME_LIVE_P (XFRAME (data->focus_frame))))
@@ -6247,6 +6371,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))
@@ -6256,19 +6381,9 @@ the return value is nil.  Otherwise the value is t.  */)
            delete_deletable_window (window);
        }
 
-      /* In the following call to `select-window', prevent "swapping out
-        point" in the old selected window using the buffer that has
-        been restored into it.  We already swapped out that point from
-        that window's old buffer.  */
-      /* This `select_window' calls record_buffer which calls Fdelq which
-        invokes QUIT, so we do it here at the end rather than earlier,
-        to minimize the risk of interrupting the Fset_window_configuration
-        in an inconsistent state (e.g. before frame-focus redirection is
-        canceled).  */
-      select_window (data->current_window, Qnil, 1);
-      BVAR (XBUFFER (XWINDOW (selected_window)->contents),
-           last_selected_window)
-       = selected_window;
+      /* 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
@@ -6504,7 +6619,8 @@ 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_1 /* 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;
@@ -6595,6 +6711,7 @@ 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 = 30;
   wset_redisplay (w);
   adjust_frame_glyphs (XFRAME (WINDOW_FRAME (w)));
 }
@@ -6798,9 +6915,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);
 }
@@ -7063,6 +7178,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);
 
@@ -7093,7 +7210,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,
@@ -7120,6 +7237,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,
@@ -7212,11 +7330,10 @@ respectively are not installed by `window-state-put'.  */);
   Vwindow_persistent_parameters = list1 (Fcons (Qclone_of, Qt));
 
   DEFVAR_BOOL ("window-resize-pixelwise", window_resize_pixelwise,
-              doc: /*  Non-nil means resizing windows works pixelwise.
-Functions currently affected by this option are `split-window',
-`maximize-window', `minimize-window', `fit-window-to-buffer' and
-`fit-frame-to-buffer' and all functions symmetrically resizing a
-parent window.
+              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
@@ -7275,6 +7392,7 @@ pixelwise even if this option is nil.  */);
   defsubr (&Swindow_header_line_height);
   defsubr (&Swindow_right_divider_width);
   defsubr (&Swindow_bottom_divider_width);
+  defsubr (&Swindow_scroll_bar_width);
   defsubr (&Swindow_inside_edges);
   defsubr (&Swindow_inside_pixel_edges);
   defsubr (&Swindow_inside_absolute_pixel_edges);