]> code.delx.au - gnu-emacs/blobdiff - src/window.c
* xfns.c (x_set_mouse_color): Recolor vertical_drag_cursor.
[gnu-emacs] / src / window.c
index bf914662df78034933eda952789d9a78a0f925bf..f42219cae940e1bc748b27d5fd22878253a42f3e 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,7 @@ 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 int displayed_window_lines (struct window *);
 static int count_windows (struct window *);
@@ -487,11 +488,14 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
     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));
+    { /* 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)
     {
@@ -510,8 +514,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);
-  if (NILP (norecord))
-    wset_redisplay (w);
 
  record_and_return:
   /* record_buffer can run QUIT, so make sure it is run only after we have
@@ -557,7 +559,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.
 
@@ -565,8 +567,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);
@@ -681,7 +692,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
@@ -694,45 +705,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,
@@ -810,62 +864,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),
@@ -873,19 +931,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),
@@ -894,7 +949,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)
 {
@@ -903,7 +958,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)
 {
@@ -912,7 +967,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)
 {
@@ -921,13 +976,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.  */)
@@ -1211,18 +1275,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
@@ -1239,12 +1303,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;
@@ -1276,6 +1341,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))
@@ -1284,9 +1350,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 ?  */
+          /* 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;
 
@@ -1297,8 +1364,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)
@@ -1308,8 +1375,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 */
@@ -1328,6 +1395,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;
 
@@ -1364,8 +1433,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,
@@ -1683,7 +1754,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;
@@ -1706,8 +1777,7 @@ overriding motion of point in order to display at this exact start.  */)
   w->update_mode_line = 1;
   /* Bug#15957.  */
   w->window_end_valid = 0;
-  if (w != XWINDOW (selected_window))
-    wset_redisplay (w);
+  wset_redisplay (w);
 
   return pos;
 }
@@ -2979,7 +3049,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;
@@ -3155,6 +3225,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;
@@ -3364,7 +3435,8 @@ 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
@@ -3646,8 +3718,10 @@ 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_NUMBER (size);
+  CHECK_RANGED_INTEGER (size, size_min, size_max);
   if (NILP (add))
     wset_new_pixel (w, size);
   else
@@ -3725,18 +3799,20 @@ window_resize_check (struct window *w, bool horflag)
        /* The sum of the heights of the child windows of W must equal
           W's height.  */
        {
-         int sum_of_pixels = 0;
+         int remaining_pixels = XINT (w->new_pixel);
 
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
 
-             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
+             remaining_pixels -= XINT (c->new_pixel);
+             if (remaining_pixels < 0)
+               return 0;
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
 
-         return (sum_of_pixels == XINT (w->new_pixel));
+         return remaining_pixels == 0;
        }
     }
   else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
@@ -3747,18 +3823,20 @@ 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_pixels = 0;
+         int remaining_pixels = XINT (w->new_pixel);
 
          while (c)
            {
              if (!window_resize_check (c, horflag))
                return 0;
 
-             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
+             remaining_pixels -= XINT (c->new_pixel);
+             if (remaining_pixels < 0)
+               return 0;
              c = NILP (c->next) ? 0 : XWINDOW (c->next);
            }
 
-         return (sum_of_pixels == XINT (w->new_pixel));
+         return remaining_pixels == 0;
        }
       else
        /* All child windows of W must have the same height as W.  */
@@ -3784,102 +3862,6 @@ window_resize_check (struct window *w, bool horflag)
                                    : FRAME_LINE_HEIGHT (f)));
 }
 
-static int
-window_resize_total_check (struct window *w, int horflag)
-{
-  struct frame *f = XFRAME (w->frame);
-  struct window *c;
-
-  if (WINDOW_VERTICAL_COMBINATION_P (w))
-    /* W is a vertical combination.  */
-    {
-      c = XWINDOW (w->contents);
-      if (horflag)
-       /* All child windows of W must have the same width as W.  */
-       {
-         while (c)
-           {
-             if (XINT (c->new_pixel) != XINT (w->new_pixel)
-/**              || XINT (c->new_total != XINT (w->new_total)) **/
-                 || !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_pixels = 0, sum_of_totals = 0;
-
-         while (c)
-           {
-             if (!window_resize_check (c, horflag))
-               return 0;
-
-             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
-/**          sum_of_totals = sum_of_totals + XINT (c->new_total); **/
-             c = NILP (c->next) ? 0 : XWINDOW (c->next);
-           }
-
-         return (sum_of_pixels == XINT (w->new_pixel)
-/**              && sum_of_totals == XINT (w->new_total) **/
-                 );
-       }
-    }
-  else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
-    /* W is a horizontal combination.  */
-    {
-      c = XWINDOW (w->contents);
-      if (horflag)
-       /* The sum of the widths of the child windows of W must equal W's
-          width.  */
-       {
-         int sum_of_pixels = 0, sum_of_totals = 0;
-
-         while (c)
-           {
-             if (!window_resize_check (c, horflag))
-               return 0;
-
-             sum_of_pixels = sum_of_pixels + XINT (c->new_pixel);
-             sum_of_totals = sum_of_totals + XINT (c->new_total);
-             c = NILP (c->next) ? 0 : XWINDOW (c->next);
-           }
-
-         return (sum_of_pixels == XINT (w->new_pixel)
-/**              && sum_of_totals == XINT (w->new_total) **/
-                 );
-       }
-      else
-       /* All child windows of W must have the same height as W.  */
-       {
-         while (c)
-           {
-             if (XINT (c->new_pixel) != XINT (w->new_pixel)
-/**              || XINT (c->new_total) != XINT (w->new_total) **/
-                 || !window_resize_check (c, horflag))
-               return 0;
-
-             c = NILP (c->next) ? 0 : XWINDOW (c->next);
-           }
-
-         return 1;
-       }
-    }
-  else
-    /* 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_pixel) >= (horflag
-                                   ? (2 * FRAME_COLUMN_WIDTH (f))
-                                   : FRAME_LINE_HEIGHT (f))
-/**        && XINT (w->new_total) >= (horflag ? 2 : 1) **/
-           );
-}
 
 /* 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.
@@ -3966,8 +3948,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;
+    }
 }
 
 
@@ -4060,7 +4045,7 @@ be applied on the Elisp level.  */)
   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);
@@ -4090,6 +4075,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;
@@ -4115,38 +4114,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)
@@ -4199,6 +4203,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
@@ -4216,6 +4221,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
                      XWINDOW (root)->pixel_height = new_pixel_size;
                    }
                }
+#endif /* 0 */
            }
        }
     }
@@ -4238,7 +4244,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
        }
     }
 
-  windows_or_buffers_changed = 31;
+  fset_redisplay (f);
 }
 
 
@@ -4340,7 +4346,7 @@ set correctly.  See the code of `split-window' for how this is done.  */)
        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
@@ -4365,7 +4371,7 @@ set correctly.  See the code of `split-window' for how this is done.  */)
   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);
@@ -4529,7 +4535,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;
 
@@ -4652,20 +4658,24 @@ grow_mini_window (struct window *w, int delta, bool pixelwise)
 
          if (pixelwise)
            {
-             pixel_height = -XINT (height);
+             pixel_height = min (-XINT (height), INT_MAX - w->pixel_height);
              line_height = pixel_height / FRAME_LINE_HEIGHT (f);
            }
          else
            {
-             line_height = -XINT (height);
+             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;
-         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?  */
@@ -4750,7 +4760,7 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
       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 ();
@@ -4820,6 +4830,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)))
@@ -5371,9 +5383,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))
@@ -5429,8 +5438,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))
@@ -5483,7 +5494,6 @@ specifies the window to scroll.  This takes precedence over
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
-  windows_or_buffers_changed = 38;
 
   Fset_buffer (w->contents);
   SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm));
@@ -5940,12 +5950,12 @@ struct save_window_data
        From `frame-cols' down, the fields are ignored by the GC.  */
     /* We should be able to do without the following two.  */
     int frame_cols, frame_lines;
-    /* These two should get eventually replaced by their pixelized
+    /* 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 pixelize
-       them.  */
+    /* These are currently unused.  We need them as soon as we convert
+       to pixels.  */
     int frame_menu_bar_height, frame_tool_bar_height;
   };
 
@@ -5992,6 +6002,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.
@@ -6071,7 +6088,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
@@ -6100,6 +6117,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 ();
@@ -6140,7 +6161,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
@@ -6297,6 +6318,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))))
@@ -6337,6 +6370,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))
@@ -6346,19 +6380,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
@@ -6685,7 +6709,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)));
 }
 
@@ -6888,9 +6913,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);
 }
@@ -7153,6 +7176,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);
 
@@ -7183,7 +7208,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,
@@ -7302,11 +7327,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
@@ -7365,6 +7389,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);