]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Update copyright year to 2015
[gnu-emacs] / src / window.c
index 6afe7454149f99f5abb770a0815695fa60b65903..938f1a3268f830191edaa8307ffa45ac720ebba4 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-2014 Free Software
+   Copyright (C) 1985-1987, 1993-1998, 2000-2015 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -52,6 +52,7 @@ 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_sanitize_window_sizes;
 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;
@@ -87,7 +88,7 @@ static struct window *set_window_fringes (struct window *, Lisp_Object,
 static struct window *set_window_margins (struct window *, Lisp_Object,
                                          Lisp_Object);
 static struct window *set_window_scroll_bars (struct window *, Lisp_Object,
-                                             Lisp_Object, Lisp_Object);
+                                             Lisp_Object, Lisp_Object, Lisp_Object);
 static void apply_window_adjustment (struct window *);
 
 /* This is the window in which the terminal's cursor should
@@ -143,66 +144,85 @@ wset_combination_limit (struct window *w, Lisp_Object val)
 {
   w->combination_limit = val;
 }
+
 static void
 wset_dedicated (struct window *w, Lisp_Object val)
 {
   w->dedicated = val;
 }
+
 static void
 wset_display_table (struct window *w, Lisp_Object val)
 {
   w->display_table = val;
 }
+
 static void
 wset_new_normal (struct window *w, Lisp_Object val)
 {
   w->new_normal = val;
 }
+
 static void
 wset_new_total (struct window *w, Lisp_Object val)
 {
   w->new_total = val;
 }
+
 static void
 wset_normal_cols (struct window *w, Lisp_Object val)
 {
   w->normal_cols = val;
 }
+
 static void
 wset_normal_lines (struct window *w, Lisp_Object val)
 {
   w->normal_lines = val;
 }
+
 static void
 wset_parent (struct window *w, Lisp_Object val)
 {
   w->parent = val;
 }
+
 static void
 wset_pointm (struct window *w, Lisp_Object val)
 {
   w->pointm = val;
 }
+
+static void
+wset_old_pointm (struct window *w, Lisp_Object val)
+{
+  w->old_pointm = val;
+}
+
 static void
 wset_start (struct window *w, Lisp_Object val)
 {
   w->start = val;
 }
+
 static void
 wset_temslot (struct window *w, Lisp_Object val)
 {
   w->temslot = val;
 }
+
 static void
 wset_vertical_scroll_bar_type (struct window *w, Lisp_Object val)
 {
   w->vertical_scroll_bar_type = val;
 }
+
 static void
 wset_window_parameters (struct window *w, Lisp_Object val)
 {
   w->window_parameters = val;
 }
+
 static void
 wset_combination (struct window *w, bool horflag, Lisp_Object val)
 {
@@ -309,7 +329,7 @@ DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
 DEFUN ("window-valid-p", Fwindow_valid_p, Swindow_valid_p, 1, 1, 0,
        doc: /* Return t if OBJECT is a valid window and nil otherwise.
 A valid window is either a window that displays a buffer or an internal
-window.  Deleted windows are not live.  */)
+window.  Windows that have been deleted are not valid.  */)
   (Lisp_Object object)
 {
   return WINDOW_VALID_P (object) ? Qt : Qnil;
@@ -790,7 +810,12 @@ total width of WINDOW.  */)
 
 DEFUN ("window-new-total", Fwindow_new_total, Swindow_new_total, 0, 1, 0,
        doc: /* Return the new total size of window WINDOW.
-WINDOW must be a valid window and defaults to the selected one.  */)
+WINDOW must be a valid window and defaults to the selected one.
+
+The new total size of WINDOW is the value set by the last call of
+`set-window-new-total' for WINDOW.  If it is valid, it will be shortly
+installed as WINDOW's total height (see `window-total-height') or total
+width (see `window-total-width').  */)
   (Lisp_Object window)
 {
   return decode_valid_window (window)->new_total;
@@ -799,7 +824,25 @@ WINDOW must be a valid window and defaults to the selected one.  */)
 DEFUN ("window-normal-size", Fwindow_normal_size, Swindow_normal_size, 0, 2, 0,
        doc: /* Return the normal height of window WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
-If HORIZONTAL is non-nil, return the normal width of WINDOW.  */)
+If HORIZONTAL is non-nil, return the normal width of WINDOW.
+
+The normal height of a frame's root window or a window that is
+horizontally combined (a window that has a left or right sibling) is
+1.0.  The normal height of a window that is vertically combined (has a
+sibling above or below) is the fraction of the window's height with
+respect to its parent.  The sum of the normal heights of all windows in a
+vertical combination equals 1.0.
+
+Similarly, the normal width of a frame's root window or a window that is
+vertically combined equals 1.0.  The normal width of a window that is
+horizontally combined is the fraction of the window's width with respect
+to its parent.  The sum of the normal widths of all windows in a
+horizontal combination equals 1.0.
+
+The normal sizes of windows are used to restore the proportional sizes
+of windows after they have been shrunk to their minimum sizes; for
+example when a frame is temporarily made very small and afterwards gets
+re-enlarged to its previous size.  */)
   (Lisp_Object window, Lisp_Object horizontal)
 {
   struct window *w = decode_valid_window (window);
@@ -809,7 +852,11 @@ If HORIZONTAL is non-nil, return the normal width of WINDOW.  */)
 
 DEFUN ("window-new-normal", Fwindow_new_normal, Swindow_new_normal, 0, 1, 0,
        doc: /* Return new normal size of window WINDOW.
-WINDOW must be a valid window and defaults to the selected one.  */)
+WINDOW must be a valid window and defaults to the selected one.
+
+The new normal size of WINDOW is the value set by the last call of
+`set-window-new-normal' for WINDOW.  If valid, it will be shortly
+installed as WINDOW's normal size (see `window-normal-size').  */)
   (Lisp_Object window)
 {
   return decode_valid_window (window)->new_normal;
@@ -817,7 +864,12 @@ WINDOW must be a valid window and defaults to the selected one.  */)
 
 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.  */)
+WINDOW must be a valid window and defaults to the selected one.
+
+The new pixel size of WINDOW is the value set by the last call of
+`set-window-new-pixel' for WINDOW.  If it is valid, it will be shortly
+installed as WINDOW's pixel height (see `window-pixel-height') or pixel
+width (see `window-pixel-width').  */)
   (Lisp_Object window)
 {
   return decode_valid_window (window)->new_pixel;
@@ -871,6 +923,9 @@ window_body_height (struct window *w, bool pixelwise)
 {
   int height = (w->pixel_height
                - WINDOW_HEADER_LINE_HEIGHT (w)
+               - (WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)
+                  ? WINDOW_SCROLL_BAR_AREA_HEIGHT (w)
+                  : 0)
                - WINDOW_MODE_LINE_HEIGHT (w)
                - WINDOW_BOTTOM_DIVIDER_WIDTH (w));
 
@@ -991,6 +1046,15 @@ WINDOW must be a live window and defaults to the selected one.  */)
   return (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (decode_live_window (window))));
 }
 
+DEFUN ("window-scroll-bar-height", Fwindow_scroll_bar_height,
+       Swindow_scroll_bar_height, 0, 1, 0,
+       doc: /* Return the height in pixels of WINDOW's horizontal scrollbar.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return (make_number (WINDOW_SCROLL_BAR_AREA_HEIGHT (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.  */)
@@ -1018,6 +1082,8 @@ set_window_hscroll (struct window *w, EMACS_INT hscroll)
     XBUFFER (w->contents)->prevent_redisplay_optimizations_p = 1;
 
   w->hscroll = new_hscroll;
+  w->suspend_auto_hscroll = 1;
+
   return make_number (new_hscroll);
 }
 
@@ -1167,12 +1233,16 @@ display margins, fringes, header line, and/or mode line.  */)
 
   return list4i ((WINDOW_BOX_LEFT_EDGE_COL (w)
                  + WINDOW_LEFT_MARGIN_COLS (w)
-                 + WINDOW_LEFT_FRINGE_COLS (w)),
+                 + ((WINDOW_LEFT_FRINGE_WIDTH (w)
+                     + WINDOW_FRAME_COLUMN_WIDTH (w) - 1)
+                    / WINDOW_FRAME_COLUMN_WIDTH (w))),
                 (WINDOW_TOP_EDGE_LINE (w)
                  + WINDOW_HEADER_LINE_LINES (w)),
                 (WINDOW_BOX_RIGHT_EDGE_COL (w)
                  - WINDOW_RIGHT_MARGIN_COLS (w)
-                 - WINDOW_RIGHT_FRINGE_COLS (w)),
+                 - ((WINDOW_RIGHT_FRINGE_WIDTH (w)
+                     + WINDOW_FRAME_COLUMN_WIDTH (w) - 1)
+                    / WINDOW_FRAME_COLUMN_WIDTH (w))),
                 (WINDOW_BOTTOM_EDGE_LINE (w)
                  - WINDOW_MODE_LINE_LINES (w)));
 }
@@ -1286,6 +1356,17 @@ coordinates_in_window (register struct window *w, int x, int y)
           && x >= right_x - WINDOW_RIGHT_DIVIDER_WIDTH (w)
           && x <= right_x)
     return ON_RIGHT_DIVIDER;
+  /* On the horizontal scroll bar?  (Including the empty space at its
+     right!)  */
+  else if ((WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w)
+           && y >= (bottom_y
+                    - WINDOW_SCROLL_BAR_AREA_HEIGHT (w)
+                    - CURRENT_MODE_LINE_HEIGHT (w)
+                    - WINDOW_BOTTOM_DIVIDER_WIDTH (w))
+           && y <= (bottom_y
+                    - CURRENT_MODE_LINE_HEIGHT (w)
+                    - WINDOW_BOTTOM_DIVIDER_WIDTH (w))))
+    return ON_HORIZONTAL_SCROLL_BAR;
   /* On the mode or header line?   */
   else if ((WINDOW_WANTS_MODELINE_P (w)
            && y >= (bottom_y
@@ -1329,7 +1410,7 @@ coordinates_in_window (register struct window *w, int x, int y)
 
   /* Outside any interesting column?  */
   if (x < left_x || x > right_x)
-    return ON_SCROLL_BAR;
+    return ON_VERTICAL_SCROLL_BAR;
 
   lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
   rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
@@ -1493,10 +1574,13 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
     case ON_RIGHT_MARGIN:
       return Qright_margin;
 
-    case ON_SCROLL_BAR:
+    case ON_VERTICAL_SCROLL_BAR:
       /* Historically we are supposed to return nil in this case.  */
       return Qnil;
 
+    case ON_HORIZONTAL_SCROLL_BAR:
+      return Qnil;
+
     case ON_RIGHT_DIVIDER:
       return Qright_divider;
 
@@ -1637,6 +1721,14 @@ correct to return the top-level value of `point', outside of any
     return Fmarker_position (w->pointm);
 }
 
+DEFUN ("window-old-point", Fwindow_old_point, Swindow_old_point, 0, 1, 0,
+       doc: /* Return old value of point in WINDOW.
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
+{
+  return Fmarker_position (decode_live_window (window)->old_pointm);
+}
+
 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
        doc: /* Return position at which display currently starts in WINDOW.
 WINDOW must be a live window and defaults to the selected one.
@@ -2915,6 +3007,7 @@ selected frame and no others.  */)
     return Qnil;
 }
 
+
 static Lisp_Object
 resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore, Lisp_Object pixelwise)
 {
@@ -2922,10 +3015,17 @@ resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizonta
 }
 
 
+Lisp_Object
+sanitize_window_sizes (Lisp_Object frame, Lisp_Object horizontal)
+{
+  return call2 (Qwindow_sanitize_window_sizes, frame, horizontal);
+}
+
+
 static Lisp_Object
 window_pixel_to_total (Lisp_Object frame, Lisp_Object horizontal)
 {
-  return call2(Qwindow_pixel_to_total, frame, horizontal);
+  return call2 (Qwindow_pixel_to_total, frame, horizontal);
 }
 
 
@@ -3204,89 +3304,6 @@ replace_buffer_in_windows_safely (Lisp_Object buffer)
        window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
     }
 }
-
-/* 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 *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.  */
-  if (pixelwise)
-    {
-      int min_height = MIN_SAFE_WINDOW_HEIGHT * FRAME_LINE_HEIGHT (frame);
-      int min_width = MIN_SAFE_WINDOW_WIDTH * FRAME_COLUMN_WIDTH (frame);
-
-      if (!FRAME_MINIBUF_ONLY_P (frame) && FRAME_HAS_MINIBUF_P (frame))
-       min_height = 2 * min_height;
-
-      min_height += FRAME_TOP_MARGIN_HEIGHT (frame);
-      min_height += FRAME_INTERNAL_BORDER_WIDTH (frame);
-
-      if (*height < min_height)
-       *height = min_height;
-      if (*width < min_width)
-       *width = min_width;
-    }
-  else
-    {
-      int min_height
-       = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
-          ? MIN_SAFE_WINDOW_HEIGHT
-          : 2 * MIN_SAFE_WINDOW_HEIGHT);
-
-      if (FRAME_TOP_MARGIN (frame) > 0)
-       min_height += FRAME_TOP_MARGIN (frame);
-
-      if (*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.
-   Return 1 if window width is ok after adjustment; 0 if window
-   is still too narrow.  */
-
-static int
-adjust_window_margins (struct window *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_width - margin_width >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
-    return 1;
-
-  if (margin_width < 0 || box_width < MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
-    return 0;
-  else
-    /* Window's text area is too narrow, but reducing the window
-       margins will fix that.  */
-    {
-      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->left_margin_cols = margin_width / unit;
-
-      return 1;
-    }
-}
 \f
 /* The following three routines are needed for running a window's
    configuration change hook.  */
@@ -3320,7 +3337,9 @@ run_window_configuration_change_hook (struct frame *f)
     = Fdefault_value (Qwindow_configuration_change_hook);
   XSETFRAME (frame, f);
 
-  if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code))
+  if (NILP (Vrun_hooks)
+      || !(f->can_x_set_window_size)
+      || !(f->can_run_window_configuration_change_hook))
     return;
 
   /* Use the right buffer.  Matters when running the local hooks.  */
@@ -3415,17 +3434,21 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
   w->last_cursor_vpos = 0;
 
   if (!(keep_margins_p && samebuf))
-    { /* If we're not actually changing the buffer, don't reset hscroll and
-        vscroll.  This case happens for example when called from
+    { /* If we're not actually changing the buffer, don't reset hscroll
+        and vscroll.  This case happens for example when called from
         change_frame_size_1, where we use a dummy call to
-        Fset_window_buffer on the frame's selected window (and no other)
-        just in order to run window-configuration-change-hook.
-        Resetting hscroll and vscroll here is problematic for things like
-        image-mode and doc-view-mode since it resets the image's position
-        whenever we resize the frame.  */
-      w->hscroll = w->min_hscroll = 0;
+        Fset_window_buffer on the frame's selected window (and no
+        other) just in order to run window-configuration-change-hook
+        (no longer true since change_frame_size_1 directly calls
+        run_window_configuration_change_hook).  Resetting hscroll and
+        vscroll here is problematic for things like image-mode and
+        doc-view-mode since it resets the image's position whenever we
+        resize the frame.  */
+      w->hscroll = w->min_hscroll = w->hscroll_whole = 0;
+      w->suspend_auto_hscroll = 0;
       w->vscroll = 0;
       set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
+      set_marker_both (w->old_pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
       set_marker_restricted (w->start,
                             make_number (b->last_window_start),
                             buffer);
@@ -3443,6 +3466,7 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
   Fset_buffer (buffer);
 
   XMARKER (w->pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
+  XMARKER (w->old_pointm)->insertion_type = !NILP (Vwindow_point_insertion_type);
 
   if (!keep_margins_p)
     {
@@ -3451,7 +3475,9 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
                          BVAR (b, right_fringe_width),
                          BVAR (b, fringes_outside_margins));
       set_window_scroll_bars (w, BVAR (b, scroll_bar_width),
-                             BVAR (b, vertical_scroll_bar_type), Qnil);
+                             BVAR (b, vertical_scroll_bar_type),
+                             BVAR (b, scroll_bar_height),
+                             BVAR (b, horizontal_scroll_bar_type));
       set_window_margins (w, BVAR (b, left_margin_cols),
                          BVAR (b, right_margin_cols));
       apply_window_adjustment (w);
@@ -3597,10 +3623,11 @@ temp_output_buffer_show (register Lisp_Object buf)
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
       Vminibuf_scroll_window = window;
       w = XWINDOW (window);
-      w->hscroll = 0;
-      w->min_hscroll = 0;
+      w->hscroll = w->min_hscroll = w->hscroll_whole = 0;
+      w->suspend_auto_hscroll = 0;
       set_marker_restricted_both (w->start, buf, BEG, BEG);
       set_marker_restricted_both (w->pointm, buf, BEG, BEG);
+      set_marker_restricted_both (w->old_pointm, buf, BEG, BEG);
 
       /* Run temp-buffer-show-hook, with the chosen window selected
         and its buffer current.  */
@@ -3652,6 +3679,7 @@ make_parent_window (Lisp_Object window, bool horflag)
   /* ...but now P becomes an internal window.  */
   wset_start (p, Qnil);
   wset_pointm (p, Qnil);
+  wset_old_pointm (p, Qnil);
   wset_buffer (p, Qnil);
   wset_combination (p, horflag, window);
   wset_combination_limit (p, Qnil);
@@ -3675,7 +3703,9 @@ make_window (void)
   wset_new_pixel (w, make_number (0));
   wset_start (w, Fmake_marker ());
   wset_pointm (w, Fmake_marker ());
+  wset_old_pointm (w, Fmake_marker ());
   wset_vertical_scroll_bar_type (w, Qt);
+  wset_horizontal_scroll_bar_type (w, Qt);
   /* These Lisp fields are marked specially so they're not set to nil by
      allocate_window.  */
   wset_prev_buffers (w, Qnil);
@@ -3692,8 +3722,8 @@ make_window (void)
 #endif
   w->sequence_number = ++sequence_number;
   w->scroll_bar_width = -1;
+  w->scroll_bar_height = -1;
   w->column_number_displayed = -1;
-
   /* Reset window_list.  */
   Vwindow_list = Qnil;
   /* Return window.  */
@@ -3709,6 +3739,10 @@ Return SIZE.
 Optional argument ADD non-nil means add SIZE to the new pixel size of
 WINDOW and return the sum.
 
+The new pixel size of WINDOW, if valid, will be shortly installed as
+WINDOW's pixel height (see `window-pixel-height') or pixel width (see
+`window-pixel-width').
+
 Note: This function does not operate on any child windows of WINDOW.  */)
   (Lisp_Object window, Lisp_Object size, Lisp_Object add)
 {
@@ -3733,6 +3767,10 @@ Return SIZE.
 Optional argument ADD non-nil means add SIZE to the new total size of
 WINDOW and return the sum.
 
+The new total size of WINDOW, if valid, will be shortly installed as
+WINDOW's total height (see `window-total-height') or total width (see
+`window-total-width').
+
 Note: This function does not operate on any child windows of WINDOW.  */)
      (Lisp_Object window, Lisp_Object size, Lisp_Object add)
 {
@@ -3752,6 +3790,9 @@ DEFUN ("set-window-new-normal", Fset_window_new_normal, Sset_window_new_normal,
 WINDOW must be a valid window and defaults to the selected one.
 Return SIZE.
 
+The new normal size of WINDOW, if valid, will be shortly installed as
+WINDOW's normal size (see `window-normal-size').
+
 Note: This function does not operate on any child windows of WINDOW.  */)
      (Lisp_Object window, Lisp_Object size)
 {
@@ -3858,7 +3899,7 @@ window_resize_check (struct window *w, bool horflag)
 }
 
 
-/* Set w->pixel_height (w->pixel_height if HORIZONTAL is non-zero) to
+/* Set w->pixel_height (w->pixel_width if HORFLAG 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.
@@ -3943,15 +3984,12 @@ window_resize_apply (struct window *w, bool horflag)
        }
     }
   else
-    {
-      adjust_window_margins (w);
-      /* Bug#15957.  */
-      w->window_end_valid = 0;
-    }
+    /* Bug#15957.  */
+    w->window_end_valid = 0;
 }
 
 
-/* Set w->total_lines (w->total_cols if HORIZONTAL is non-zero) to
+/* Set w->total_lines (w->total_cols if HORFLAG 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.  */
@@ -4019,9 +4057,14 @@ If FRAME is omitted or nil, it defaults to the selected frame.
 Optional argument HORIZONTAL omitted or nil means apply requested
 height values.  HORIZONTAL non-nil means apply requested width values.
 
-This function checks whether the requested values sum up to a valid
-window layout, recursively assigns the new sizes of all child windows
-and calculates and assigns the new start positions of these windows.
+The requested size values are those set by `set-window-new-pixel' and
+`set-window-new-normal'.  This function checks whether the requested
+values sum up to a valid window layout, recursively assigns the new
+sizes of all child windows and calculates and assigns the new start
+positions of these windows.
+
+Return t if the requested values have been applied correctly, nil
+otherwise.
 
 Note: This function does not check any of `window-fixed-size-p',
 `window-min-height' or `window-min-width'.  All these checks have to
@@ -4092,11 +4135,7 @@ values.  */)
 
 /* 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.  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.  */
+   SIZE.  PIXELWISE 1 means to interpret SIZE as pixels.  */
 void
 resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
 {
@@ -4107,6 +4146,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
   /* 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;
+  int old_pixel_top = r->pixel_top;
   /* 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);
@@ -4121,7 +4161,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
       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)),
@@ -4133,7 +4172,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
       new_size = max (horflag
                      ? size
                      : (size
-                        - FRAME_TOP_MARGIN (f)
                         - ((FRAME_HAS_MINIBUF_P (f)
                             && !FRAME_MINIBUF_ONLY_P (f))
                            ? 1 : 0)),
@@ -4144,7 +4182,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
   r->top_line = FRAME_TOP_MARGIN (f);
   r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
 
-  if (new_pixel_size == old_pixel_size)
+  if (new_pixel_size == old_pixel_size
+      && r->pixel_top == old_pixel_top)
     ;
   else if (WINDOW_LEAF_P (r))
     /* For a leaf root window just set the size.  */
@@ -4186,6 +4225,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 safe sizes and/or killing other windows.  */
            }
          else
            {
@@ -4198,7 +4238,6 @@ 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
@@ -4402,7 +4441,9 @@ set correctly.  See the code of `split-window' for how this is done.  */)
   n->right_fringe_width = r->right_fringe_width;
   n->fringes_outside_margins = r->fringes_outside_margins;
   n->scroll_bar_width = r->scroll_bar_width;
+  n->scroll_bar_height = r->scroll_bar_height;
   wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type);
+  wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type);
 
   /* Directly assign orthogonal coordinates and sizes.  */
   if (horflag)
@@ -4546,6 +4587,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
        {
          unshow_buffer (w);
          unchain_marker (XMARKER (w->pointm));
+         unchain_marker (XMARKER (w->old_pointm));
          unchain_marker (XMARKER (w->start));
          wset_buffer (w, Qnil);
        }
@@ -4750,10 +4792,10 @@ DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini
       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->total_lines = w->pixel_height / FRAME_LINE_HEIGHT (f);
       w->pixel_top = r->pixel_top + r->pixel_height;
+      w->top_line = r->top_line + r->total_lines;
 
       fset_redisplay (f);
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
@@ -4807,6 +4849,7 @@ window_internal_height (struct window *w)
 
   return ht;
 }
+
 \f
 /************************************************************************
                           Window Scrolling
@@ -4822,11 +4865,16 @@ window_internal_height (struct window *w)
 static void
 window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror)
 {
+  ptrdiff_t count = SPECPDL_INDEX ();
+
   immediate_quit = 1;
   n = clip_to_bounds (INT_MIN, n, INT_MAX);
 
   wset_redisplay (XWINDOW (window));
 
+  if (whole && Vfast_but_imprecise_scrolling)
+    specbind (Qfontification_functions, Qnil);
+
   /* 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)))
@@ -4834,6 +4882,8 @@ window_scroll (Lisp_Object window, EMACS_INT n, bool whole, int noerror)
   else
     window_scroll_line_based (window, n, whole, noerror);
 
+  unbind_to (count, Qnil);
+
   /* Bug#15957.  */
   XWINDOW (window)->window_end_valid = 0;
   immediate_quit = 0;
@@ -4857,6 +4907,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
   void *itdata = NULL;
   int window_total_lines;
   int frame_line_height = default_line_pixel_height (w);
+  bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window),
+                                         Fwindow_old_point (window)));
 
   SET_TEXT_POS_FROM_MARKER (start, w->start);
   /* Scrolling a minibuffer window via scroll bar when the echo area
@@ -4883,8 +4935,8 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
       /* The function move_iterator_vertically may move over more than
         the specified y-distance.  If it->w is small, e.g. a
         mini-buffer window, we may end up in front of the window's
-        display area.  This is the case when Start displaying at the
-        start of the line containing PT in this case.  */
+        display area.  Start displaying at the start of the line
+        containing PT in this case.  */
       if (it.current_y <= 0)
        {
          init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
@@ -4901,9 +4953,14 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
        {
          int px;
          int dy = frame_line_height;
+         /* In the below we divide the window box height by the
+            frame's line height to make the result predictable when
+            the window box is not an integral multiple of the line
+            height.  This is important to ensure we get back to the
+            same position when scrolling up, then down.  */
          if (whole)
-           dy = max ((window_box_height (w)
-                      - next_screen_context_lines * dy),
+           dy = max ((window_box_height (w) / dy
+                      - next_screen_context_lines) * dy,
                      dy);
          dy *= n;
 
@@ -4985,8 +5042,12 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
     {
       ptrdiff_t start_pos = IT_CHARPOS (it);
       int dy = frame_line_height;
-      dy = max ((window_box_height (w)
-                - next_screen_context_lines * dy),
+      /* In the below we divide the window box height by the frame's
+        line height to make the result predictable when the window
+        box is not an integral multiple of the line height.  This is
+        important to ensure we get back to the same position when
+        scrolling up, then down.  */
+      dy = max ((window_box_height (w) / dy - next_screen_context_lines) * dy,
                dy) * n;
 
       /* Note that move_it_vertically always moves the iterator to the
@@ -5228,6 +5289,13 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, int noerror)
        }
     }
   bidi_unshelve_cache (itdata, 0);
+
+  if (adjust_old_pointm)
+    Fset_marker (w->old_pointm,
+                ((w == XWINDOW (selected_window))
+                 ? make_number (BUF_PT (XBUFFER (w->contents)))
+                 : Fmarker_position (w->pointm)),
+                w->contents);
 }
 
 
@@ -5252,6 +5320,8 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror)
   ptrdiff_t startpos = marker_position (w->start);
   ptrdiff_t startbyte = marker_byte_position (w->start);
   Lisp_Object original_pos = Qnil;
+  bool adjust_old_pointm = !NILP (Fequal (Fwindow_point (window),
+                                         Fwindow_old_point (window)));
 
   /* If scrolling screen-fulls, compute the number of lines to
      scroll from the window's height.  */
@@ -5267,6 +5337,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror)
          struct position posit
            = *compute_motion (startpos, startbyte, 0, 0, 0,
                               PT, ht, 0, -1, w->hscroll, 0, w);
+
          window_scroll_preserve_vpos = posit.vpos;
          window_scroll_preserve_hpos = posit.hpos + w->hscroll;
        }
@@ -5382,6 +5453,13 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, int noerror)
       else
        xsignal0 (Qend_of_buffer);
     }
+
+  if (adjust_old_pointm)
+    Fset_marker (w->old_pointm,
+                ((w == XWINDOW (selected_window))
+                 ? make_number (BUF_PT (XBUFFER (w->contents)))
+                 : Fmarker_position (w->pointm)),
+                w->contents);
 }
 
 
@@ -5518,6 +5596,7 @@ specifies the window to scroll.  This takes precedence over
 
   Fset_buffer (w->contents);
   SET_PT_BOTH (marker_position (w->pointm), marker_byte_position (w->pointm));
+  SET_PT_BOTH (marker_position (w->old_pointm), marker_byte_position (w->old_pointm));
 
   if (NILP (arg))
     window_scroll (window, 1, 1, 1);
@@ -5532,6 +5611,7 @@ specifies the window to scroll.  This takes precedence over
     }
 
   set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
+  set_marker_both (w->old_pointm, Qnil, PT, PT_BYTE);
   unbind_to (count, Qnil);
 
   return Qnil;
@@ -5557,6 +5637,8 @@ by this function.  This happens in an interactive call.  */)
   if (!NILP (set_minimum))
     w->min_hscroll = w->hscroll;
 
+  w->suspend_auto_hscroll = 1;
+
   return result;
 }
 
@@ -5580,6 +5662,8 @@ by this function.  This happens in an interactive call.  */)
   if (!NILP (set_minimum))
     w->min_hscroll = w->hscroll;
 
+  w->suspend_auto_hscroll = 1;
+
   return result;
 }
 
@@ -5677,7 +5761,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
   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.  */
   buf->display_error_modiff = 0;
 
@@ -5843,38 +5927,52 @@ and redisplay normally--don't erase and redraw the frame.  */)
   w->start_at_line_beg = (bytepos == BEGV_BYTE
                          || FETCH_BYTE (bytepos - 1) == '\n');
 
+  wset_redisplay (w);
+
   return Qnil;
 }
 
 DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width,
-       0, 1, 0,
+       0, 2, 0,
        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 width does not include dividers, scrollbars, margins,
 fringes, nor any partial-width columns at the right of the text
-area.  */)
-  (Lisp_Object window)
+area.
+
+Optional argument PIXELWISE non-nil, means to return the width in
+pixels.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
 {
   struct window *w = decode_live_window (window);
 
-  return make_number (window_box_width (w, TEXT_AREA)
-                     / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)));
+  if (NILP (pixelwise))
+    return make_number (window_box_width (w, TEXT_AREA)
+                       / FRAME_COLUMN_WIDTH (WINDOW_XFRAME (w)));
+  else
+    return make_number (window_box_width (w, TEXT_AREA));
 }
 
 DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
-       0, 1, 0,
+       0, 2, 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)
+line, nor any partial-height lines at the bottom of the text area.
+
+Optional argument PIXELWISE non-nil, means to return the height in
+pixels.  */)
+  (Lisp_Object window, Lisp_Object pixelwise)
 {
   struct window *w = decode_live_window (window);
 
-  return make_number (window_box_height (w)
-                     / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)));
+  if (NILP (pixelwise))
+    return make_number (window_box_height (w)
+                       / FRAME_LINE_HEIGHT (WINDOW_XFRAME (w)));
+  else
+    return make_number (window_box_height (w));
 }
 \f
 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
@@ -5984,17 +6082,18 @@ struct saved_window
 {
   struct vectorlike_header header;
 
-  Lisp_Object window, buffer, start, pointm;
+  Lisp_Object window, buffer, start, pointm, old_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;
+  Lisp_Object hscroll, min_hscroll, hscroll_whole, suspend_auto_hscroll;
   Lisp_Object parent, prev;
   Lisp_Object start_at_line_beg;
   Lisp_Object display_table;
   Lisp_Object left_margin_cols, right_margin_cols;
   Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
   Lisp_Object scroll_bar_width, vertical_scroll_bar_type, dedicated;
+  Lisp_Object scroll_bar_height, horizontal_scroll_bar_type;
   Lisp_Object combination_limit, window_parameters;
 };
 
@@ -6022,13 +6121,6 @@ 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.
@@ -6045,6 +6137,7 @@ the return value is nil.  Otherwise the value is t.  */)
   Lisp_Object frame;
   struct frame *f;
   ptrdiff_t old_point = -1;
+  USE_SAFE_ALLOCA;
 
   CHECK_WINDOW_CONFIGURATION (configuration);
 
@@ -6108,19 +6201,6 @@ 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_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);
 
       /* Don't do this within the main loop below: This may call Lisp
         code and is thus potentially unsafe while input is blocked.  */
@@ -6137,36 +6217,12 @@ 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;
+      /* Disallow x_set_window_size, temporarily.  */
+      f->can_x_set_window_size = false;
       /* The mouse highlighting code could get screwed up
         if it runs during this.  */
       block_input ();
 
-      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))
-           x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
-                                 make_number (0));
-         else  /* TTY or MSDOS */
-#endif
-           set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
-                               make_number (0));
-       }
-#ifdef HAVE_WINDOW_SYSTEM
-      if (data->frame_tool_bar_lines != previous_frame_tool_bar_lines)
-       x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
-                             make_number (0));
-#endif
-
       /* "Swap out" point from the selected window's buffer
         into the window itself.  (Normally the pointm of the selected
         window holds garbage.)  We do this now, before
@@ -6189,8 +6245,8 @@ the return value is nil.  Otherwise the value is t.  */)
         really like to do is to free only those matrices not reused
         below.  */
       root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
-      leaf_windows = alloca (count_windows (root_window)
-                            * sizeof *leaf_windows);
+      int nwindows = count_windows (root_window);
+      SAFE_NALLOCA (leaf_windows, 1, nwindows);
       n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
 
       /* Kludge Alert!
@@ -6245,7 +6301,9 @@ the return value is nil.  Otherwise the value is t.  */)
          wset_normal_cols (w, p->normal_cols);
          wset_normal_lines (w, p->normal_lines);
          w->hscroll = XFASTINT (p->hscroll);
+         w->suspend_auto_hscroll = !NILP (p->suspend_auto_hscroll);
          w->min_hscroll = XFASTINT (p->min_hscroll);
+         w->hscroll_whole = XFASTINT (p->hscroll_whole);
          wset_display_table (w, p->display_table);
          w->left_margin_cols = XINT (p->left_margin_cols);
          w->right_margin_cols = XINT (p->right_margin_cols);
@@ -6253,7 +6311,9 @@ the return value is nil.  Otherwise the value is t.  */)
          w->right_fringe_width = XINT (p->right_fringe_width);
          w->fringes_outside_margins = !NILP (p->fringes_outside_margins);
          w->scroll_bar_width = XINT (p->scroll_bar_width);
+         w->scroll_bar_height = XINT (p->scroll_bar_height);
          wset_vertical_scroll_bar_type (w, p->vertical_scroll_bar_type);
+         wset_horizontal_scroll_bar_type (w, p->horizontal_scroll_bar_type);
          wset_dedicated (w, p->dedicated);
          wset_combination_limit (w, p->combination_limit);
          /* Restore any window parameters that have been saved.
@@ -6284,16 +6344,15 @@ the return value is nil.  Otherwise the value is t.  */)
              wset_buffer (w, p->buffer);
              w->start_at_line_beg = !NILP (p->start_at_line_beg);
              set_marker_restricted (w->start, p->start, w->contents);
-             set_marker_restricted (w->pointm, p->pointm,
-                                    w->contents);
-
+             set_marker_restricted (w->pointm, p->pointm, w->contents);
+             set_marker_restricted (w->old_pointm, p->old_pointm, w->contents);
              /* As documented in Fcurrent_window_configuration, don't
                 restore the location of point in the buffer which was
                 current when the window configuration was recorded.  */
              if (!EQ (p->buffer, new_current_buffer)
                  && XBUFFER (p->buffer) == current_buffer)
                Fgoto_char (w->pointm);
-            }
+           }
          else if (BUFFERP (w->contents) && BUFFER_LIVE_P (XBUFFER (w->contents)))
            /* Keep window's old buffer; make sure the markers are real.  */
            {
@@ -6305,20 +6364,26 @@ the return value is nil.  Otherwise the value is t.  */)
                  (w->pointm, w->contents,
                   BUF_PT (XBUFFER (w->contents)),
                   BUF_PT_BYTE (XBUFFER (w->contents)));
+             if (XMARKER (w->old_pointm)->buffer == 0)
+               set_marker_restricted_both
+                 (w->old_pointm, w->contents,
+                  BUF_PT (XBUFFER (w->contents)),
+                  BUF_PT_BYTE (XBUFFER (w->contents)));
              w->start_at_line_beg = 1;
            }
          else if (!NILP (w->start))
            /* Leaf window has no live buffer, get one.  */
            {
              /* Get the buffer via other_buffer_safely in order to
-             avoid showing an unimportant buffer and, if necessary, to
-             recreate *scratch* in the course (part of Juanma's bs-show
-             scenario from March 2011).  */
+                avoid showing an unimportant buffer and, if necessary, to
+                recreate *scratch* in the course (part of Juanma's bs-show
+                scenario from March 2011).  */
              wset_buffer (w, other_buffer_safely (Fcurrent_buffer ()));
              /* This will set the markers to beginning of visible
                 range.  */
              set_marker_restricted_both (w->start, w->contents, 0, 0);
              set_marker_restricted_both (w->pointm, w->contents, 0, 0);
+             set_marker_restricted_both (w->old_pointm, w->contents, 0, 0);
              w->start_at_line_beg = 1;
              if (!NILP (w->dedicated))
                /* Record this window as dead.  */
@@ -6353,30 +6418,6 @@ 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 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
-         if (FRAME_WINDOW_P (f))
-           x_set_menu_bar_lines (f,
-                                 make_number (previous_frame_menu_bar_lines),
-                                 make_number (0));
-         else  /* TTY or MSDOS */
-#endif
-           set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
-                               make_number (0));
-       }
-#ifdef HAVE_WINDOW_SYSTEM
-      if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
-       x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
-                             make_number (0));
-#endif
-
       /* Now, free glyph matrices in windows that were not reused.  */
       for (i = n = 0; i < n_leaf_windows; ++i)
        {
@@ -6386,9 +6427,13 @@ the return value is nil.  Otherwise the value is t.  */)
            ++n;
        }
 
+      /* Allow x_set_window_size again and apply frame size changes if
+        needed.  */
+      f->can_x_set_window_size = true;
+      adjust_frame_size (f, -1, -1, 1, 0, Qnil);
+
       adjust_frame_glyphs (f);
       unblock_input ();
-      unbind_to (count, Qnil);
 
       /* Scan dead buffer windows.  */
       for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
@@ -6425,9 +6470,11 @@ the return value is nil.  Otherwise the value is t.  */)
   Vminibuf_scroll_window = data->minibuf_scroll_window;
   minibuf_selected_window = data->minibuf_selected_window;
 
+  SAFE_FREE ();
   return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 
+
 void
 restore_window_configuration (Lisp_Object configuration)
 {
@@ -6459,6 +6506,7 @@ delete_all_child_windows (Lisp_Object window)
     {
       unshow_buffer (w);
       unchain_marker (XMARKER (w->pointm));
+      unchain_marker (XMARKER (w->old_pointm));
       unchain_marker (XMARKER (w->start));
       /* Since combination limit makes sense for an internal windows
         only, we use this slot to save the buffer for the sake of
@@ -6565,7 +6613,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
       p->normal_cols = w->normal_cols;
       p->normal_lines = w->normal_lines;
       XSETFASTINT (p->hscroll, w->hscroll);
+      p->suspend_auto_hscroll = w->suspend_auto_hscroll ? Qt : Qnil;
       XSETFASTINT (p->min_hscroll, w->min_hscroll);
+      XSETFASTINT (p->hscroll_whole, w->hscroll_whole);
       p->display_table = w->display_table;
       p->left_margin_cols = make_number (w->left_margin_cols);
       p->right_margin_cols = make_number (w->right_margin_cols);
@@ -6573,7 +6623,9 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
       p->right_fringe_width = make_number (w->right_fringe_width);
       p->fringes_outside_margins = w->fringes_outside_margins ? Qt : Qnil;
       p->scroll_bar_width = make_number (w->scroll_bar_width);
+      p->scroll_bar_height = make_number (w->scroll_bar_height);
       p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
+      p->horizontal_scroll_bar_type = w->horizontal_scroll_bar_type;
       p->dedicated = w->dedicated;
       p->combination_limit = w->combination_limit;
       p->window_parameters = Qnil;
@@ -6635,9 +6687,13 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
                                      BUF_PT_BYTE (XBUFFER (w->contents)));
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
+         p->old_pointm = Fcopy_marker (w->old_pointm, Qnil);
          XMARKER (p->pointm)->insertion_type
            = !NILP (buffer_local_value /* Don't signal error if void.  */
                     (Qwindow_point_insertion_type, w->contents));
+         XMARKER (p->old_pointm)->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;
@@ -6645,6 +6701,7 @@ save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
       else
        {
          p->pointm = Qnil;
+         p->old_pointm = Qnil;
          p->start = Qnil;
          p->start_at_line_beg = Qnil;
        }
@@ -6714,7 +6771,6 @@ static void
 apply_window_adjustment (struct window *w)
 {
   eassert (w);
-  adjust_window_margins (w);
   clear_glyph_matrix (w->current_matrix);
   w->window_end_valid = 0;
   windows_or_buffers_changed = 30;
@@ -6732,8 +6788,8 @@ set_window_margins (struct window *w, Lisp_Object left_width,
                    Lisp_Object right_width)
 {
   int left, right;
+  int unit = WINDOW_FRAME_COLUMN_WIDTH (w);
 
-  /* FIXME: what about margins that are too wide?  */
   left = (NILP (left_width) ? 0
          : (CHECK_NATNUM (left_width), XINT (left_width)));
   right = (NILP (right_width) ? 0
@@ -6741,11 +6797,23 @@ set_window_margins (struct window *w, Lisp_Object left_width,
 
   if (w->left_margin_cols != left || w->right_margin_cols != right)
     {
-      w->left_margin_cols = left;
-      w->right_margin_cols = right;
-      return w;
+      /* Don't change anything if new margins won't fit.  */
+      if ((WINDOW_PIXEL_WIDTH (w)
+          - WINDOW_FRINGES_WIDTH (w)
+          - WINDOW_SCROLL_BAR_AREA_WIDTH (w)
+          - (left + right) * unit)
+         >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
+       {
+         w->left_margin_cols = left;
+         w->right_margin_cols = right;
+
+         return w;
+       }
+      else
+       return NULL;
     }
-  return NULL;
+  else
+    return NULL;
 }
 
 DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
@@ -6807,12 +6875,25 @@ set_window_fringes (struct window *w, Lisp_Object left_width,
          || w->right_fringe_width != right
          || w->fringes_outside_margins != outside))
     {
+      if (left > 0 || right > 0)
+       {
+         /* Don't change anything if new fringes don't fit.  */
+         if ((WINDOW_PIXEL_WIDTH (w)
+              - WINDOW_MARGINS_WIDTH (w)
+              - WINDOW_SCROLL_BAR_AREA_WIDTH (w)
+              - max (left, 0) - max (right, 0))
+             < MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
+           return NULL;
+       }
+
       w->left_fringe_width = left;
       w->right_fringe_width = right;
       w->fringes_outside_margins = outside;
+
       return w;
     }
-  return NULL;
+  else
+    return NULL;
 }
 
 DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
@@ -6863,9 +6944,11 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
 
 static struct window *
 set_window_scroll_bars (struct window *w, Lisp_Object width,
-                       Lisp_Object vertical_type, Lisp_Object horizontal_type)
+                       Lisp_Object vertical_type, Lisp_Object height,
+                       Lisp_Object horizontal_type)
 {
   int iwidth = (NILP (width) ? -1 : (CHECK_NATNUM (width), XINT (width)));
+  bool changed = 0;
 
   if (iwidth == 0)
     vertical_type = Qnil;
@@ -6879,32 +6962,78 @@ set_window_scroll_bars (struct window *w, Lisp_Object width,
   if (w->scroll_bar_width != iwidth
       || !EQ (w->vertical_scroll_bar_type, vertical_type))
     {
-      w->scroll_bar_width = iwidth;
-      wset_vertical_scroll_bar_type (w, vertical_type);
-      return w;
+      /* Don't change anything if new scroll bar won't fit.  */
+      if ((WINDOW_PIXEL_WIDTH (w)
+          - WINDOW_MARGINS_WIDTH (w)
+          - WINDOW_FRINGES_WIDTH (w)
+          - max (iwidth, 0))
+         >= MIN_SAFE_WINDOW_PIXEL_WIDTH (w))
+       {
+         w->scroll_bar_width = iwidth;
+         wset_vertical_scroll_bar_type (w, vertical_type);
+         changed = 1;
+       }
     }
-  return NULL;
+
+#if USE_HORIZONTAL_SCROLL_BARS
+  {
+    int iheight = (NILP (height) ? -1 : (CHECK_NATNUM (height), XINT (height)));
+
+    if (MINI_WINDOW_P (w) || iheight == 0)
+      horizontal_type = Qnil;
+
+    if (!(NILP (horizontal_type)
+         || EQ (horizontal_type, Qbottom)
+         || EQ (horizontal_type, Qt)))
+      error ("Invalid type of horizontal scroll bar");
+
+    if (w->scroll_bar_height != iheight
+       || !EQ (w->horizontal_scroll_bar_type, horizontal_type))
+      {
+       /* Don't change anything if new scroll bar won't fit.  */
+       if ((WINDOW_PIXEL_HEIGHT (w)
+            - WINDOW_HEADER_LINE_HEIGHT (w)
+            - WINDOW_MODE_LINE_HEIGHT (w)
+            - max (iheight, 0))
+           >= MIN_SAFE_WINDOW_PIXEL_HEIGHT (w))
+         {
+           w->scroll_bar_height = iheight;
+           wset_horizontal_scroll_bar_type (w, horizontal_type);
+           changed = 1;
+         }
+      }
+  }
+#else
+  wset_horizontal_scroll_bar_type (w, Qnil);
+#endif
+
+  return changed ? w : NULL;
 }
 
 DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars,
-       Sset_window_scroll_bars, 2, 4, 0,
+       Sset_window_scroll_bars, 1, 5, 0,
        doc: /* Set width and type of scroll bars of window WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
-Second parameter WIDTH specifies the pixel width for the scroll bar.
+Second parameter WIDTH specifies the pixel width for the vertical scroll
+bar.  If WIDTH is nil, use the scroll-bar width of WINDOW's frame.
 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.
+bar: left, right, or nil.  If VERTICAL-TYPE is t, this means use the
+frame's scroll-bar type.
+
+Fourth parameter HEIGHT specifies the pixel height for the horizontal
+scroll bar.  If HEIGHT is nil, use the scroll-bar height of WINDOW's
+frame.  Fifth parameter HORIZONTAL-TYPE specifies the type of the
+horizontal scroll bar: nil, bottom, or t.  If HORIZONTAL-TYPE is t, this
+means to use the frame's horizontal scroll-bar type.
 
 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)
+  (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type,
+   Lisp_Object height, Lisp_Object horizontal_type)
 {
   struct window *w
     = set_window_scroll_bars (decode_live_window (window),
-                             width, vertical_type, horizontal_type);
+                             width, vertical_type, height, horizontal_type);
   return w ? (apply_window_adjustment (w), Qt) : Qnil;
 }
 
@@ -6914,19 +7043,25 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
        doc: /* Get width and type of scroll bars of window WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
-Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
-If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
+Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES
+HORIZONTAL-TYPE).  If WIDTH or HEIGHT is nil or VERTICAL-TYPE or
+HORIZONTAL-TYPE is t, the window is using the frame's corresponding
 value.  */)
   (Lisp_Object window)
 {
   struct window *w = decode_live_window (window);
 
-  return list4 (make_number (WINDOW_SCROLL_BAR_AREA_WIDTH (w)),
-               make_number (WINDOW_SCROLL_BAR_COLS (w)),
-               w->vertical_scroll_bar_type, Qnil);
+  return Fcons (((w->scroll_bar_width >= 0)
+                ? make_number (w->scroll_bar_width)
+                : Qnil),
+               list5 (make_number (WINDOW_SCROLL_BAR_COLS (w)),
+                      w->vertical_scroll_bar_type,
+                      ((w->scroll_bar_height >= 0)
+                       ? make_number (w->scroll_bar_height)
+                       : Qnil),
+                      make_number (WINDOW_SCROLL_BAR_LINES (w)),
+                      w->horizontal_scroll_bar_type));
 }
-
-
 \f
 /***********************************************************************
                           Smooth scrolling
@@ -7116,7 +7251,9 @@ compare_window_configurations (Lisp_Object configuration1,
          || !EQ (sw1->right_fringe_width, sw2->right_fringe_width)
          || !EQ (sw1->fringes_outside_margins, sw2->fringes_outside_margins)
          || !EQ (sw1->scroll_bar_width, sw2->scroll_bar_width)
-         || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type))
+         || !EQ (sw1->scroll_bar_height, sw2->scroll_bar_height)
+         || !EQ (sw1->vertical_scroll_bar_type, sw2->vertical_scroll_bar_type)
+         || !EQ (sw1->horizontal_scroll_bar_type, sw2->horizontal_scroll_bar_type))
        return 0;
     }
 
@@ -7170,6 +7307,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_sanitize_window_sizes, "window--sanitize-window-sizes");
   DEFSYM (Qwindow_pixel_to_total, "window--pixel-to-total");
   DEFSYM (Qsafe, "safe");
   DEFSYM (Qdisplay_buffer, "display-buffer");
@@ -7210,7 +7348,7 @@ the buffer; `temp-buffer-show-hook' is not run unless this function runs it.  */
               doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
 If the minibuffer is active, the `minibuffer-scroll-window' mode line
 is displayed in the `mode-line' face.  */);
-  mode_line_in_non_selected_windows = 1;
+  mode_line_in_non_selected_windows = true;
 
   DEFVAR_LISP ("other-window-scroll-buffer", Vother_window_scroll_buffer,
               doc: /* If this is a live buffer, \\[scroll-other-window] should scroll its window.  */);
@@ -7218,7 +7356,7 @@ is displayed in the `mode-line' face.  */);
 
   DEFVAR_BOOL ("auto-window-vscroll", auto_window_vscroll_p,
               doc: /* Non-nil means to automatically adjust `window-vscroll' to view tall lines.  */);
-  auto_window_vscroll_p = 1;
+  auto_window_vscroll_p = true;
 
   DEFVAR_INT ("next-screen-context-lines", next_screen_context_lines,
              doc: /* Number of lines of continuity when scrolling by screenfuls.  */);
@@ -7341,7 +7479,18 @@ 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;
+  window_resize_pixelwise = false;
+
+  DEFVAR_BOOL ("fast-but-imprecise-scrolling",
+               Vfast_but_imprecise_scrolling,
+               doc: /* When non-nil, accelerate scrolling operations.
+This comes into play when scrolling rapidly over previously
+unfontified buffer regions.  Only those portions of the buffer which
+are actually going to be displayed get fontified.
+
+Note that this optimization can cause the portion of the buffer
+displayed after a scrolling operation to be somewhat inaccurate.  */);
+  Vfast_but_imprecise_scrolling = false;
 
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
@@ -7396,12 +7545,14 @@ pixelwise even if this option is nil.  */);
   defsubr (&Swindow_right_divider_width);
   defsubr (&Swindow_bottom_divider_width);
   defsubr (&Swindow_scroll_bar_width);
+  defsubr (&Swindow_scroll_bar_height);
   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_old_point);
   defsubr (&Swindow_start);
   defsubr (&Swindow_end);
   defsubr (&Sset_window_point);