* alloc.c, bytecode.c, ccl.c, coding.c, composite.c, data.c, dosfns.c:
[bpt/emacs.git] / src / window.c
index 5688b4a..9420d73 100644 (file)
@@ -1,7 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
-                 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+   Copyright (C) 1985-1987, 1993-1998, 2000-2012
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -24,6 +23,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <setjmp.h>
 
 #include "lisp.h"
+#include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
 #include "keymap.h"
@@ -51,41 +51,41 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "nsterm.h"
 #endif
 
-
-Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
-Lisp_Object Qdisplay_buffer;
-Lisp_Object Qscroll_up, Qscroll_down;
-Lisp_Object Qwindow_size_fixed;
-
-extern Lisp_Object Qleft_margin, Qright_margin;
-
-static int displayed_window_lines P_ ((struct window *));
-static struct window *decode_window P_ ((Lisp_Object));
-static int count_windows P_ ((struct window *));
-static int get_leaf_windows P_ ((struct window *, struct window **, int));
-static void window_scroll P_ ((Lisp_Object, int, int, int));
-static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
-static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
-static int window_min_size_1 P_ ((struct window *, int, int));
-static int window_min_size_2 P_ ((struct window *, int, int));
-static int window_min_size P_ ((struct window *, int, int, int, int *));
-static void size_window P_ ((Lisp_Object, int, int, int, int, int));
-static int freeze_window_start P_ ((struct window *, void *));
-static int window_fixed_size_p P_ ((struct window *, int, int));
-static void enlarge_window P_ ((Lisp_Object, int, int));
-static Lisp_Object window_list P_ ((void));
-static int add_window_to_list P_ ((struct window *, void *));
-static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
-                                  Lisp_Object));
-static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
-                                   Lisp_Object, int));
-static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
-                                        Lisp_Object *));
-static int foreach_window_1 P_ ((struct window *,
+Lisp_Object Qwindowp, Qwindow_live_p;
+static Lisp_Object Qwindow_configuration_p, 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 Qscroll_up, Qscroll_down, Qscroll_command;
+static Lisp_Object Qsafe, Qabove, Qbelow;
+static Lisp_Object Qauto_buffer_name, Qclone_of;
+
+static int displayed_window_lines (struct window *);
+static struct window *decode_window (Lisp_Object);
+static int count_windows (struct window *);
+static int get_leaf_windows (struct window *, struct window **, int);
+static void window_scroll (Lisp_Object, EMACS_INT, int, int);
+static void window_scroll_pixel_based (Lisp_Object, int, int, int);
+static void window_scroll_line_based (Lisp_Object, int, int, int);
+static int freeze_window_start (struct window *, void *);
+static Lisp_Object window_list (void);
+static int add_window_to_list (struct window *, void *);
+static int candidate_window_p (Lisp_Object, Lisp_Object, Lisp_Object,
+                               Lisp_Object);
+static Lisp_Object next_window (Lisp_Object, Lisp_Object,
+                                Lisp_Object, int);
+static void decode_next_window_args (Lisp_Object *, Lisp_Object *,
+                                     Lisp_Object *);
+static void foreach_window (struct frame *,
                                 int (* fn) (struct window *, void *),
-                                void *));
-static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
-static Lisp_Object select_window P_ ((Lisp_Object, Lisp_Object, int));
+                            void *);
+static int foreach_window_1 (struct window *,
+                             int (* fn) (struct window *, void *),
+                             void *);
+static Lisp_Object window_list_1 (Lisp_Object, Lisp_Object, Lisp_Object);
+static int window_resize_check (struct window *, int);
+static void window_resize_apply (struct window *, int);
+static Lisp_Object select_window (Lisp_Object, Lisp_Object, int);
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -94,193 +94,114 @@ static Lisp_Object select_window P_ ((Lisp_Object, Lisp_Object, int));
 
    This value is always the same as
    FRAME_SELECTED_WINDOW (selected_frame).  */
-
 Lisp_Object selected_window;
 
 /* A list of all windows for use by next_window and Fwindow_list.
    Functions creating or deleting windows should invalidate this cache
    by setting it to nil.  */
-
 Lisp_Object Vwindow_list;
 
 /* The mini-buffer window of the selected frame.
    Note that you cannot test for mini-bufferness of an arbitrary window
    by comparing against this; but you can test for mini-bufferness of
    the selected window.  */
-
 Lisp_Object minibuf_window;
 
 /* Non-nil means it is the window whose mode line should be
    shown as the selected window when the minibuffer is selected.  */
-
 Lisp_Object minibuf_selected_window;
 
-/* Non-nil means it is the window for C-M-v to scroll
-   when the mini-buffer is selected.  */
-
-Lisp_Object Vminibuf_scroll_window;
-
-/* Non-nil means this is the buffer whose window C-M-v should scroll.  */
-
-Lisp_Object Vother_window_scroll_buffer;
-
-/* Non-nil means it's function to call to display temp buffers.  */
-
-Lisp_Object Vtemp_buffer_show_function;
-
-/* Non-zero means line and page scrolling on tall lines (with images)
-   does partial scrolling by modifying window-vscroll.  */
-
-int auto_window_vscroll_p;
-
-/* Non-zero means to use mode-line-inactive face in all windows but the
-   selected-window and the minibuffer-scroll-window when the
-   minibuffer is active.  */
-int mode_line_in_non_selected_windows;
-
-/* If a window gets smaller than either of these, it is removed. */
-
-EMACS_INT window_min_height;
-EMACS_INT window_min_width;
-
 /* Hook run at end of temp_output_buffer_show.  */
-
-Lisp_Object Qtemp_buffer_show_hook;
-
-/* Number of lines of continuity in scrolling by screenfuls.  */
-
-EMACS_INT next_screen_context_lines;
+static Lisp_Object Qtemp_buffer_show_hook;
 
 /* Incremented for each window created.  */
-
 static int sequence_number;
 
 /* Nonzero after init_window_once has finished.  */
-
 static int window_initialized;
 
 /* Hook to run when window config changes.  */
-
 static Lisp_Object Qwindow_configuration_change_hook;
-static Lisp_Object Vwindow_configuration_change_hook;
-
-/* Non-nil means scroll commands try to put point
-   at the same screen height as previously.  */
-
-Lisp_Object Vscroll_preserve_screen_position;
-
-/* Non-nil means that text is inserted before window's markers.  */
-
-Lisp_Object Vwindow_point_insertion_type;
-
-/* Incremented by 1 whenever a window is deleted.  */
-
-int window_deletion_count;
 
 /* Used by the function window_scroll_pixel_based */
-
 static int window_scroll_pixel_based_preserve_x;
 static int window_scroll_pixel_based_preserve_y;
 
 /* Same for window_scroll_line_based.  */
+static EMACS_INT window_scroll_preserve_hpos;
+static EMACS_INT window_scroll_preserve_vpos;
+\f
+static struct window *
+decode_window (register Lisp_Object window)
+{
+  if (NILP (window))
+    return XWINDOW (selected_window);
 
-static int window_scroll_preserve_hpos;
-static int window_scroll_preserve_vpos;
-
-extern EMACS_INT scroll_margin;
-
-extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
+  CHECK_LIVE_WINDOW (window);
+  return XWINDOW (window);
+}
 
-/* If non-nil, then the `recenter' command with a nil argument
-   the entire frame to be redrawn; the special value `tty' causes the
-   frame to be redrawn only if it is a tty frame.  */
+static struct window *
+decode_any_window (register Lisp_Object window)
+{
+  if (NILP (window))
+    return XWINDOW (selected_window);
 
-static Lisp_Object Vrecenter_redisplay;
-extern Lisp_Object Qtty;
+  CHECK_WINDOW (window);
+  return XWINDOW (window);
+}
 
-\f
 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
-       doc: /* Return t if OBJECT is a window.  */)
-     (object)
-     Lisp_Object object;
+       doc: /* Return t if OBJECT is a window and nil otherwise.  */)
+  (Lisp_Object object)
 {
   return WINDOWP (object) ? Qt : Qnil;
 }
 
 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
-       doc: /* Return t if OBJECT is a window which is currently visible.  */)
-     (object)
-     Lisp_Object object;
+       doc: /* Return t if OBJECT is a live window and nil otherwise.
+A live window is a window that displays a buffer.
+Internal windows and deleted windows are not live.  */)
+  (Lisp_Object object)
 {
   return WINDOW_LIVE_P (object) ? Qt : Qnil;
 }
-
-Lisp_Object
-make_window ()
+\f
+/* Frames and windows.  */
+DEFUN ("window-frame", Fwindow_frame, Swindow_frame, 1, 1, 0,
+       doc: /* Return the frame that window WINDOW is on.
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
 {
-  Lisp_Object val;
-  register struct window *p;
-
-  p = allocate_window ();
-  ++sequence_number;
-  XSETFASTINT (p->sequence_number, sequence_number);
-  XSETFASTINT (p->left_col, 0);
-  XSETFASTINT (p->top_line, 0);
-  XSETFASTINT (p->total_lines, 0);
-  XSETFASTINT (p->total_cols, 0);
-  XSETFASTINT (p->hscroll, 0);
-  XSETFASTINT (p->min_hscroll, 0);
-  p->orig_top_line = p->orig_total_lines = Qnil;
-  p->start = Fmake_marker ();
-  p->pointm = Fmake_marker ();
-  XSETFASTINT (p->use_time, 0);
-  p->frame = Qnil;
-  p->display_table = Qnil;
-  p->dedicated = Qnil;
-  p->window_parameters = Qnil;
-  p->pseudo_window_p = 0;
-  bzero (&p->cursor, sizeof (p->cursor));
-  bzero (&p->last_cursor, sizeof (p->last_cursor));
-  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
-  p->desired_matrix = p->current_matrix = 0;
-  p->nrows_scale_factor = p->ncols_scale_factor = 1;
-  p->phys_cursor_type = -1;
-  p->phys_cursor_width = -1;
-  p->must_be_updated_p = 0;
-  XSETFASTINT (p->window_end_vpos, 0);
-  XSETFASTINT (p->window_end_pos, 0);
-  p->window_end_valid = Qnil;
-  p->vscroll = 0;
-  XSETWINDOW (val, p);
-  XSETFASTINT (p->last_point, 0);
-  p->frozen_window_start_p = 0;
-  p->last_cursor_off_p = p->cursor_off_p = 0;
-  p->left_margin_cols = Qnil;
-  p->right_margin_cols = Qnil;
-  p->left_fringe_width = Qnil;
-  p->right_fringe_width = Qnil;
-  p->fringes_outside_margins = Qnil;
-  p->scroll_bar_width = Qnil;
-  p->vertical_scroll_bar_type = Qt;
-  p->resize_proportionally = Qnil;
-
-  Vwindow_list = Qnil;
-  return val;
+  return decode_any_window (window)->frame;
 }
 
-DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
-       doc: /* Return the window that the cursor now appears in and commands apply to.  */)
-     ()
+DEFUN ("frame-root-window", Fframe_root_window, Sframe_root_window, 0, 1, 0,
+       doc: /* Return the root window of FRAME-OR-WINDOW.
+If omitted, FRAME-OR-WINDOW defaults to the currently selected frame.
+With a frame argument, return that frame's root window.
+With a window argument, return the root window of that window's frame.  */)
+  (Lisp_Object frame_or_window)
 {
-  return selected_window;
+  Lisp_Object window;
+
+  if (NILP (frame_or_window))
+    window = SELECTED_FRAME ()->root_window;
+  else if (WINDOWP (frame_or_window))
+    window = XFRAME (WINDOW_FRAME (XWINDOW (frame_or_window)))->root_window;
+  else
+    {
+      CHECK_LIVE_FRAME (frame_or_window);
+      window = XFRAME (frame_or_window)->root_window;
+    }
+
+  return window;
 }
 
 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
-       doc: /* Return the window used now for minibuffers.
-If the optional argument FRAME is specified, return the minibuffer window
-used by that frame.  */)
-     (frame)
-    Lisp_Object frame;
+       doc: /* Return the minibuffer window for frame FRAME.
+If FRAME is omitted or nil, it defaults to the selected frame.  */)
+  (Lisp_Object frame)
 {
   if (NILP (frame))
     frame = selected_frame;
@@ -288,286 +209,482 @@ used by that frame.  */)
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
 
-DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
+DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p,
+       Swindow_minibuffer_p, 0, 1, 0,
        doc: /* Return non-nil if WINDOW is a minibuffer window.
-WINDOW defaults to the selected window.  */)
-     (window)
-     Lisp_Object window;
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
 {
-  struct window *w = decode_window (window);
-  return MINI_WINDOW_P (w) ? Qt : Qnil;
+  return MINI_WINDOW_P (decode_any_window (window)) ? Qt : Qnil;
 }
 
-
-DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
-       Spos_visible_in_window_p, 0, 3, 0,
-       doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
-Return nil if that position is scrolled vertically out of view.
-If a character is only partially visible, nil is returned, unless the
-optional argument PARTIALLY is non-nil.
-If POS is only out of view because of horizontal scrolling, return non-nil.
-If POS is t, it specifies the position of the last visible glyph in WINDOW.
-POS defaults to point in WINDOW; WINDOW defaults to the selected window.
-
-If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
-return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
-where X and Y are the pixel coordinates relative to the top left corner
-of the window.  The remaining elements are omitted if the character after
-POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
-off-window at the top and bottom of the row, ROWH is the height of the
-display row, and VPOS is the row number (0-based) containing POS.  */)
-     (pos, window, partially)
-     Lisp_Object pos, window, partially;
+/* Don't move this to window.el - this must be a safe routine.  */
+DEFUN ("frame-first-window", Fframe_first_window, Sframe_first_window, 0, 1, 0,
+       doc: /* Return the topmost, leftmost live window on FRAME-OR-WINDOW.
+If omitted, FRAME-OR-WINDOW defaults to the currently selected frame.
+Else if FRAME-OR-WINDOW denotes any window, return the first window of
+that window's frame.  If FRAME-OR-WINDOW denotes a live frame, return
+the first window of that frame.  */)
+  (Lisp_Object frame_or_window)
 {
-  register struct window *w;
-  register int posint;
-  register struct buffer *buf;
-  struct text_pos top;
-  Lisp_Object in_window = Qnil;
-  int rtop, rbot, rowh, vpos, fully_p = 1;
-  int x, y;
+  Lisp_Object window;
 
-  w = decode_window (window);
-  buf = XBUFFER (w->buffer);
-  SET_TEXT_POS_FROM_MARKER (top, w->start);
+  if (NILP (frame_or_window))
+    window = SELECTED_FRAME ()->root_window;
+  else if (WINDOWP (frame_or_window))
+    window = XFRAME (WINDOW_FRAME (XWINDOW (frame_or_window)))->root_window;
+  else
+    {
+      CHECK_LIVE_FRAME (frame_or_window);
+      window = XFRAME (frame_or_window)->root_window;
+    }
 
-  if (EQ (pos, Qt))
-    posint = -1;
-  else if (!NILP (pos))
+  while (NILP (XWINDOW (window)->buffer))
     {
-      CHECK_NUMBER_COERCE_MARKER (pos);
-      posint = XINT (pos);
+      if (! NILP (XWINDOW (window)->hchild))
+       window = XWINDOW (window)->hchild;
+      else if (! NILP (XWINDOW (window)->vchild))
+       window = XWINDOW (window)->vchild;
+      else
+       abort ();
     }
-  else if (w == XWINDOW (selected_window))
-    posint = PT;
-  else
-    posint = XMARKER (w->pointm)->charpos;
 
-  /* If position is above window start or outside buffer boundaries,
-     or if window start is out of range, position is not visible.  */
-  if ((EQ (pos, Qt)
-       || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
-      && CHARPOS (top) >= BUF_BEGV (buf)
-      && CHARPOS (top) <= BUF_ZV (buf)
-      && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
-      && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
-    in_window = Qt;
+  return window;
+}
 
-  if (!NILP (in_window) && !NILP (partially))
+DEFUN ("frame-selected-window", Fframe_selected_window,
+       Sframe_selected_window, 0, 1, 0,
+       doc: /* Return the selected window of FRAME-OR-WINDOW.
+If omitted, FRAME-OR-WINDOW defaults to the currently selected frame.
+Else if FRAME-OR-WINDOW denotes any window, return the selected window
+of that window's frame.  If FRAME-OR-WINDOW denotes a live frame, return
+the selected window of that frame.  */)
+  (Lisp_Object frame_or_window)
+{
+  Lisp_Object window;
+
+  if (NILP (frame_or_window))
+    window = SELECTED_FRAME ()->selected_window;
+  else if (WINDOWP (frame_or_window))
+    window = XFRAME (WINDOW_FRAME (XWINDOW (frame_or_window)))->selected_window;
+  else
     {
-      Lisp_Object part = Qnil;
-      if (!fully_p)
-       part = list4 (make_number (rtop), make_number (rbot),
-                       make_number (rowh), make_number (vpos));
-      in_window = Fcons (make_number (x),
-                        Fcons (make_number (y), part));
+      CHECK_LIVE_FRAME (frame_or_window);
+      window = XFRAME (frame_or_window)->selected_window;
     }
 
-  return in_window;
+  return window;
 }
 
-DEFUN ("window-line-height", Fwindow_line_height,
-       Swindow_line_height, 0, 2, 0,
-       doc: /* Return height in pixels of text line LINE in window WINDOW.
-If WINDOW is nil or omitted, use selected window.
+DEFUN ("set-frame-selected-window", Fset_frame_selected_window,
+       Sset_frame_selected_window, 2, 3, 0,
+       doc: /* Set selected window of FRAME to WINDOW.
+FRAME must be a live frame and defaults to the selected one.  If FRAME
+is the selected frame, this makes WINDOW the selected window.  Optional
+argument NORECORD non-nil means to neither change the order of recently
+selected windows nor the buffer list.  WINDOW must denote a live window.
+Return WINDOW.  */)
+  (Lisp_Object frame, Lisp_Object window, Lisp_Object norecord)
+{
+  if (NILP (frame))
+    frame = selected_frame;
 
-Return height of current line if LINE is omitted or nil.  Return height of
-header or mode line if LINE is `header-line' and `mode-line'.
-Otherwise, LINE is a text line number starting from 0.  A negative number
-counts from the end of the window.
+  CHECK_LIVE_FRAME (frame);
+  CHECK_LIVE_WINDOW (window);
 
-Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
-in pixels of the visible part of the line, VPOS and YPOS are the
-vertical position in lines and pixels of the line, relative to the top
-of the first text line, and OFFBOT is the number of off-window pixels at
-the bottom of the text line.  If there are off-window pixels at the top
-of the (first) text line, YPOS is negative.
+  if (! EQ (frame, WINDOW_FRAME (XWINDOW (window))))
+    error ("In `set-frame-selected-window', WINDOW is not on FRAME");
 
-Return nil if window display is not up-to-date.  In that case, use
-`pos-visible-in-window-p' to obtain the information.  */)
-     (line, window)
-     Lisp_Object line, window;
+  if (EQ (frame, selected_frame))
+    return Fselect_window (window, norecord);
+  else
+    return XFRAME (frame)->selected_window = window;
+}
+
+DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
+       doc: /* Return the selected window.
+The selected window is the window in which the standard cursor for
+selected windows appears and to which many commands apply.  */)
+  (void)
 {
-  register struct window *w;
-  register struct buffer *b;
-  struct glyph_row *row, *end_row;
-  int max_y, crop, i, n;
+  return selected_window;
+}
 
-  w = decode_window (window);
+int window_select_count;
 
-  if (noninteractive
-      || w->pseudo_window_p)
-    return Qnil;
+/* If select_window is called with inhibit_point_swap non-zero it will
+   not store point of the old selected window's buffer back into that
+   window's pointm slot.  This is needed by Fset_window_configuration to
+   avoid that the display routine is called with selected_window set to
+   Qnil causing a subsequent crash.  */
+static Lisp_Object
+select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
+{
+  register struct window *w;
+  register struct window *ow;
+  struct frame *sf;
 
-  CHECK_BUFFER (w->buffer);
-  b = XBUFFER (w->buffer);
+  CHECK_LIVE_WINDOW (window);
 
-  /* Fail if current matrix is not up-to-date.  */
-  if (NILP (w->window_end_valid)
-      || current_buffer->clip_changed
-      || current_buffer->prevent_redisplay_optimizations_p
-      || XFASTINT (w->last_modified) < BUF_MODIFF (b)
-      || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
-    return Qnil;
+  w = XWINDOW (window);
+  w->frozen_window_start_p = 0;
 
-  if (NILP (line))
+  if (NILP (norecord))
     {
-      i = w->cursor.vpos;
-      if (i < 0 || i >= w->current_matrix->nrows
-         || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
-       return Qnil;
-      max_y = window_text_bottom_y (w);
-      goto found_row;
+      ++window_select_count;
+      XSETFASTINT (w->use_time, window_select_count);
+      record_buffer (w->buffer);
     }
 
-  if (EQ (line, Qheader_line))
+  if (EQ (window, selected_window) && !inhibit_point_swap)
+    return window;
+
+  sf = SELECTED_FRAME ();
+  if (XFRAME (WINDOW_FRAME (w)) != sf)
     {
-      if (!WINDOW_WANTS_HEADER_LINE_P (w))
-       return Qnil;
-      row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
-      if (!row->enabled_p)
-       return Qnil;
-      return list4 (make_number (row->height),
-                   make_number (0), make_number (0),
-                   make_number (0));
+      XFRAME (WINDOW_FRAME (w))->selected_window = window;
+      /* Use this rather than Fhandle_switch_frame
+        so that FRAME_FOCUS_FRAME is moved appropriately as we
+        move around in the state where a minibuffer in a separate
+        frame is active.  */
+      Fselect_frame (WINDOW_FRAME (w), norecord);
+      /* Fselect_frame called us back so we've done all the work already.  */
+      eassert (EQ (window, selected_window));
+      return window;
     }
+  else
+    sf->selected_window = window;
 
-  if (EQ (line, Qmode_line))
+  /* Store the current buffer's actual point into the
+     old selected window.  It belongs to that window,
+     and when the window is not selected, must be in the window.  */
+  if (!inhibit_point_swap)
     {
-      row = MATRIX_MODE_LINE_ROW (w->current_matrix);
-      if (!row->enabled_p)
-       return Qnil;
-      return list4 (make_number (row->height),
-                   make_number (0), /* not accurate */
-                   make_number (WINDOW_HEADER_LINE_HEIGHT (w)
-                                + window_text_bottom_y (w)),
-                   make_number (0));
+      ow = XWINDOW (selected_window);
+      if (! NILP (ow->buffer))
+       set_marker_both (ow->pointm, ow->buffer,
+                        BUF_PT (XBUFFER (ow->buffer)),
+                        BUF_PT_BYTE (XBUFFER (ow->buffer)));
     }
 
-  CHECK_NUMBER (line);
-  n = XINT (line);
-
-  row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
-  end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
-  max_y = window_text_bottom_y (w);
-  i = 0;
+  selected_window = window;
 
-  while ((n < 0 || i < n)
-        && row <= end_row && row->enabled_p
-        && row->y + row->height < max_y)
-    row++, i++;
+  Fset_buffer (w->buffer);
 
-  if (row > end_row || !row->enabled_p)
-    return Qnil;
+  BVAR (XBUFFER (w->buffer), last_selected_window) = window;
 
-  if (++n < 0)
-    {
-      if (-n > i)
-       return Qnil;
-      row += n;
-      i += n;
-    }
+  /* Go to the point recorded in the window.
+     This is important when the buffer is in more
+     than one window.  It also matters when
+     redisplay_window has altered point after scrolling,
+     because it makes the change only in the window.  */
+  {
+    register ptrdiff_t new_point = marker_position (w->pointm);
+    if (new_point < BEGV)
+      SET_PT (BEGV);
+    else if (new_point > ZV)
+      SET_PT (ZV);
+    else
+      SET_PT (new_point);
+  }
 
- found_row:
-  crop = max (0, (row->y + row->height) - max_y);
-  return list4 (make_number (row->height + min (0, row->y) - crop),
-               make_number (i),
-               make_number (row->y),
-               make_number (crop));
+  windows_or_buffers_changed++;
+  return window;
 }
 
+DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
+       doc: /* Select WINDOW.  Most editing will apply to WINDOW's buffer.
+Also make WINDOW's buffer current and make WINDOW the frame's selected
+window.  Return WINDOW.
+
+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.  */)
+  (register Lisp_Object window, Lisp_Object norecord)
+{
+  return select_window (window, norecord, 0);
+}
 \f
-static struct window *
-decode_window (window)
-     register Lisp_Object window;
+DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
+       doc: /* Return the buffer displayed in window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Return nil for an internal window or a deleted window.  */)
+  (Lisp_Object window)
 {
-  if (NILP (window))
-    return XWINDOW (selected_window);
+  return decode_any_window (window)->buffer;
+}
 
-  CHECK_LIVE_WINDOW (window);
-  return XWINDOW (window);
+DEFUN ("window-parent", Fwindow_parent, Swindow_parent, 0, 1, 0,
+       doc: /* Return the parent window of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Return nil for a window with no parent (e.g. a root window).  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->parent;
 }
 
-static struct window *
-decode_any_window (window)
-     register Lisp_Object window;
+DEFUN ("window-top-child", Fwindow_top_child, Swindow_top_child, 1, 1, 0,
+       doc: /* Return the topmost child window of window WINDOW.
+Return nil if WINDOW is a live window (live windows have no children).
+Return nil if WINDOW is an internal window whose children form a
+horizontal combination.  */)
+  (Lisp_Object window)
 {
-  if (NILP (window))
-    return XWINDOW (selected_window);
+  CHECK_WINDOW (window);
+  return decode_any_window (window)->vchild;
+}
 
+DEFUN ("window-left-child", Fwindow_left_child, Swindow_left_child, 1, 1, 0,
+       doc: /* Return the leftmost child window of window WINDOW.
+Return nil if WINDOW is a live window (live windows have no children).
+Return nil if WINDOW is an internal window whose children form a
+vertical combination.  */)
+  (Lisp_Object window)
+{
   CHECK_WINDOW (window);
-  return XWINDOW (window);
+  return decode_any_window (window)->hchild;
 }
 
-DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
-       doc: /* Return the buffer that WINDOW is displaying.
-WINDOW defaults to the selected window.  */)
-     (window)
-     Lisp_Object window;
+DEFUN ("window-next-sibling", Fwindow_next_sibling, Swindow_next_sibling, 0, 1, 0,
+       doc: /* Return the next sibling window of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Return nil if WINDOW has no next sibling.  */)
+  (Lisp_Object window)
 {
-  return decode_window (window)->buffer;
+  return decode_any_window (window)->next;
 }
 
-DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
-       doc: /* Return the number of lines in WINDOW.
-WINDOW defaults to the selected window.
+DEFUN ("window-prev-sibling", Fwindow_prev_sibling, Swindow_prev_sibling, 0, 1, 0,
+       doc: /* Return the previous sibling window of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Return nil if WINDOW has no previous sibling.  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->prev;
+}
+
+DEFUN ("window-combination-limit", Fwindow_combination_limit, Swindow_combination_limit, 1, 1, 0,
+       doc: /* Return combination limit of window WINDOW.
+If the return value is nil, child windows of WINDOW can be recombined with
+WINDOW's siblings.  A return value of t means that child windows of
+WINDOW are never \(re-)combined with WINDOW's siblings.  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->combination_limit;
+}
+
+DEFUN ("set-window-combination-limit", Fset_window_combination_limit, Sset_window_combination_limit, 2, 2, 0,
+       doc: /* Set combination limit of window WINDOW to LIMIT; return LIMIT.
+If LIMIT is nil, child windows of WINDOW can be recombined with
+WINDOW's siblings.  LIMIT t means that child windows of WINDOW are
+never \(re-)combined with WINDOW's siblings.  Other values are reserved
+for future use.  */)
+  (Lisp_Object window, Lisp_Object limit)
+{
+  register struct window *w = decode_any_window (window);
+
+  w->combination_limit = limit;
+
+  return w->combination_limit;
+}
+
+DEFUN ("window-use-time", Fwindow_use_time, Swindow_use_time, 0, 1, 0,
+       doc: /* Return the use time of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+The window with the highest use time is the most recently selected
+one.  The window with the lowest use time is the least recently
+selected one.  */)
+  (Lisp_Object window)
+{
+  return decode_window (window)->use_time;
+}
+\f
+DEFUN ("window-total-height", Fwindow_total_height, Swindow_total_height, 0, 1, 0,
+       doc: /* Return the total height, in lines, of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
 
-The return value includes WINDOW's mode line and header line, if any.
+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.
 
-Note: The function does not take into account the value of `line-spacing'
-when calculating the number of lines in WINDOW.  */)
-     (window)
-     Lisp_Object window;
+On a graphical display, this total height is reported as an
+integer multiple of the default character height.  */)
+  (Lisp_Object window)
 {
   return decode_any_window (window)->total_lines;
 }
 
-DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
-       doc: /* Return the number of display columns in WINDOW.
-WINDOW defaults to the selected window.
+DEFUN ("window-total-width", Fwindow_total_width, Swindow_total_width, 0, 1, 0,
+       doc: /* Return the total width, in columns, of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
 
-Note: The return value is the number of columns available for text in
-WINDOW.  If you want to find out how many columns WINDOW takes up, use
-(let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).  */)
-     (window)
-     Lisp_Object window;
+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)
 {
-  return make_number (window_box_text_cols (decode_any_window (window)));
+  return decode_any_window (window)->total_cols;
 }
 
-DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
-       doc: /* Return t if WINDOW is as wide as its frame.
-WINDOW defaults to the selected window.  */)
-     (window)
-     Lisp_Object window;
+DEFUN ("window-new-total", Fwindow_new_total, Swindow_new_total, 0, 1, 0,
+       doc: /* Return the new total size of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.   */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->new_total;
+}
+
+DEFUN ("window-normal-size", Fwindow_normal_size, Swindow_normal_size, 0, 2, 0,
+       doc: /* Return the normal height of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.
+If HORIZONTAL is non-nil, return the normal width of WINDOW.  */)
+  (Lisp_Object window, Lisp_Object horizontal)
+{
+  if (NILP (horizontal))
+    return decode_any_window (window)->normal_lines;
+  else
+    return decode_any_window (window)->normal_cols;
+}
+
+DEFUN ("window-new-normal", Fwindow_new_normal, Swindow_new_normal, 0, 1, 0,
+       doc: /* Return new normal size of window WINDOW.
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->new_normal;
+}
+
+DEFUN ("window-left-column", Fwindow_left_column, Swindow_left_column, 0, 1, 0,
+       doc: /* Return left column of window WINDOW.
+This is the distance, in columns, between the left edge of WINDOW and
+the left edge of the frame's window area.  For instance, the return
+value is 0 if there is no window to the left of WINDOW.
+
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->left_col;
+}
+
+DEFUN ("window-top-line", Fwindow_top_line, Swindow_top_line, 0, 1, 0,
+       doc: /* Return top line of window WINDOW.
+This is the distance, in lines, between the top of WINDOW and the top
+of the frame's window area.  For instance, the return value is 0 if
+there is no window above WINDOW.
+
+If WINDOW is omitted or nil, it defaults to the selected window.  */)
+  (Lisp_Object window)
+{
+  return decode_any_window (window)->top_line;
+}
+
+/* Return the number of lines of W's body.  Don't count any mode or
+   header line of W.  */
+
+static int
+window_body_lines (struct window *w)
+{
+  int height = XFASTINT (w->total_lines);
+
+  if (!MINI_WINDOW_P (w))
+    {
+      if (WINDOW_WANTS_MODELINE_P (w))
+       --height;
+      if (WINDOW_WANTS_HEADER_LINE_P (w))
+       --height;
+    }
+
+  return height;
+}
+
+/* Return the number of columns of W's body.  Don't count columns
+   occupied by the scroll bar or the vertical bar separating W from its
+   right sibling.  On window-systems don't count fringes or display
+   margins either.  */
+
+int
+window_body_cols (struct window *w)
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int width = XINT (w->total_cols);
+
+  if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+    /* Scroll bars occupy a few columns.  */
+    width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
+  else if (!FRAME_WINDOW_P (f)
+          && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+    /* The column of `|' characters separating side-by-side windows
+       occupies one column only.  */
+    width -= 1;
+
+  if (FRAME_WINDOW_P (f))
+    /* On window-systems, fringes and display margins cannot be
+       used for normal text.  */
+    width -= (WINDOW_FRINGE_COLS (w)
+             + WINDOW_LEFT_MARGIN_COLS (w)
+             + WINDOW_RIGHT_MARGIN_COLS (w));
+
+  return width;
+}
+
+DEFUN ("window-body-height", Fwindow_body_height, Swindow_body_height, 0, 1, 0,
+       doc: /* Return the height, in lines, of WINDOW's text area.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Signal an error if the window is not live.
+
+The returned height does not include the mode line or header line.
+On a graphical display, the height is expressed as an integer multiple
+of the default character height.  If a line at the bottom of the text
+area is only partially visible, that counts as a whole line; to
+exclude partially-visible lines, use `window-text-height'.  */)
+  (Lisp_Object window)
+{
+  struct window *w = decode_window (window);
+  return make_number (window_body_lines (w));
+}
+
+DEFUN ("window-body-width", Fwindow_body_width, Swindow_body_width, 0, 1, 0,
+       doc: /* Return the width, in columns, of WINDOW's text area.
+If WINDOW is omitted or nil, it defaults to the selected window.
+Signal an error if the window is not live.
+
+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.  */)
+  (Lisp_Object window)
 {
-  return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
+  struct window *w = decode_window (window);
+  return make_number (window_body_cols (w));
 }
 
 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 defaults to the selected window.  */)
-     (window)
-     Lisp_Object window;
+WINDOW must be a live window and defaults to the selected one.  */)
+  (Lisp_Object window)
 {
   return decode_window (window)->hscroll;
 }
 
 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
        doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
+If WINDOW is nil, the selected window is used.
 Return NCOL.  NCOL should be zero or positive.
 
 Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
 window so that the location of point moves off-window.  */)
-     (window, ncol)
-     Lisp_Object window, ncol;
+  (Lisp_Object window, Lisp_Object ncol)
 {
   struct window *w = decode_window (window);
-  int hscroll;
+  ptrdiff_t hscroll;
 
   CHECK_NUMBER (ncol);
-  hscroll = max (0, XINT (ncol));
+  hscroll = clip_to_bounds (0, XINT (ncol), PTRDIFF_MAX);
 
   /* Prevent redisplay shortcuts when changing the hscroll.  */
   if (XINT (w->hscroll) != hscroll)
@@ -582,8 +699,7 @@ DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
        doc: /* Return WINDOW's redisplay end trigger value.
 WINDOW defaults to the selected window.
 See `set-window-redisplay-end-trigger' for more information.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   return decode_window (window)->redisplay_end_trigger;
 }
@@ -596,8 +712,7 @@ If it is a buffer position, then if redisplay in WINDOW reaches a position
 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
 with two arguments: WINDOW, and the end trigger value.
 Afterwards the end-trigger value is reset to nil.  */)
-     (window, value)
-     register Lisp_Object window, value;
+  (register Lisp_Object window, Lisp_Object value)
 {
   register struct window *w;
 
@@ -617,8 +732,7 @@ BOTTOM is one more than the bottommost row occupied by WINDOW.
 The edges include the space used by WINDOW's scroll bar, display
 margins, fringes, header line, and/or mode line.  For the edges of
 just the text area, use `window-inside-edges'.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   register struct window *w = decode_any_window (window);
 
@@ -639,8 +753,7 @@ BOTTOM is one more than the bottommost y position occupied by WINDOW.
 The pixel edges include the space used by WINDOW's scroll bar, display
 margins, fringes, header line, and/or mode line.  For the pixel edges
 of just the text area, use `window-inside-pixel-edges'.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   register struct window *w = decode_any_window (window);
 
@@ -651,6 +764,52 @@ of just the text area, use `window-inside-pixel-edges'.  */)
                Qnil))));
 }
 
+static void
+calc_absolute_offset (struct window *w, int *add_x, int *add_y)
+{
+  struct frame *f = XFRAME (w->frame);
+  *add_y = f->top_pos;
+#ifdef FRAME_MENUBAR_HEIGHT
+  *add_y += FRAME_MENUBAR_HEIGHT (f);
+#endif
+#ifdef FRAME_TOOLBAR_TOP_HEIGHT
+  *add_y += FRAME_TOOLBAR_TOP_HEIGHT (f);
+#elif FRAME_TOOLBAR_HEIGHT
+  *add_y += FRAME_TOOLBAR_HEIGHT (f);
+#endif
+#ifdef FRAME_NS_TITLEBAR_HEIGHT
+  *add_y += FRAME_NS_TITLEBAR_HEIGHT (f);
+#endif
+  *add_x = f->left_pos;
+#ifdef FRAME_TOOLBAR_LEFT_WIDTH
+  *add_x += FRAME_TOOLBAR_LEFT_WIDTH (f);
+#endif
+}
+
+DEFUN ("window-absolute-pixel-edges", Fwindow_absolute_pixel_edges,
+       Swindow_absolute_pixel_edges, 0, 1, 0,
+       doc: /* Return a list of the edge pixel coordinates of WINDOW.
+The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
+the top left corner of the display.
+
+RIGHT is one more than the rightmost x position occupied by WINDOW.
+BOTTOM is one more than the bottommost y position occupied by WINDOW.
+The pixel edges include the space used by WINDOW's scroll bar, display
+margins, fringes, header line, and/or mode line.  For the pixel edges
+of just the text area, use `window-inside-absolute-pixel-edges'.  */)
+  (Lisp_Object window)
+{
+  register struct window *w = decode_any_window (window);
+  int add_x, add_y;
+  calc_absolute_offset (w, &add_x, &add_y);
+
+  return Fcons (make_number (WINDOW_LEFT_EDGE_X (w) + add_x),
+         Fcons (make_number (WINDOW_TOP_EDGE_Y (w) + add_y),
+        Fcons (make_number (WINDOW_RIGHT_EDGE_X (w) + add_x),
+        Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w) + add_y),
+               Qnil))));
+}
+
 DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
        doc: /* Return a list of the edge coordinates of WINDOW.
 The list has the form (LEFT TOP RIGHT BOTTOM).
@@ -661,10 +820,9 @@ RIGHT is one more than the rightmost column of WINDOW's text area.
 BOTTOM is one more than the bottommost row of WINDOW's text area.
 The inside edges do not include the space used by the WINDOW's scroll
 bar, display margins, fringes, header line, and/or mode line.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
-  register struct window *w = decode_any_window (window);
+  register struct window *w = decode_window (window);
 
   return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
                             + WINDOW_LEFT_MARGIN_COLS (w)
@@ -679,18 +837,17 @@ bar, display margins, fringes, header line, and/or mode line.  */)
 }
 
 DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge pixel coordinates of WINDOW.
-The list has the form (LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at
-the top left corner of the frame.
+       doc: /* Return a list of the edge pixel coordinates of WINDOW's text area.
+The list has the form (LEFT TOP RIGHT BOTTOM), all relative to (0,0)
+at the top left corner of the frame's window area.
 
 RIGHT is one more than the rightmost x position of WINDOW's text area.
 BOTTOM is one more than the bottommost y position of WINDOW's text area.
 The inside edges do not include the space used by WINDOW's scroll bar,
 display margins, fringes, header line, and/or mode line.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
-  register struct window *w = decode_any_window (window);
+  register struct window *w = decode_window (window);
 
   return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
                             + WINDOW_LEFT_MARGIN_WIDTH (w)
@@ -704,134 +861,109 @@ display margins, fringes, header line, and/or mode line.  */)
                             - WINDOW_MODE_LINE_HEIGHT (w)));
 }
 
-/* Test if the character at column *X, row *Y is within window W.
+DEFUN ("window-inside-absolute-pixel-edges",
+       Fwindow_inside_absolute_pixel_edges,
+       Swindow_inside_absolute_pixel_edges, 0, 1, 0,
+       doc: /* Return a list of the edge pixel coordinates of WINDOW's text area.
+The list has the form (LEFT TOP RIGHT BOTTOM), all relative to (0,0)
+at the top left corner of the frame's window area.
+
+RIGHT is one more than the rightmost x position of WINDOW's text area.
+BOTTOM is one more than the bottommost y position of WINDOW's text area.
+The inside edges do not include the space used by WINDOW's scroll bar,
+display margins, fringes, header line, and/or mode line.  */)
+  (Lisp_Object window)
+{
+  register struct window *w = decode_window (window);
+  int add_x, add_y;
+  calc_absolute_offset (w, &add_x, &add_y);
+
+  return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
+                            + WINDOW_LEFT_MARGIN_WIDTH (w)
+                            + WINDOW_LEFT_FRINGE_WIDTH (w) + add_x),
+               make_number (WINDOW_TOP_EDGE_Y (w)
+                            + WINDOW_HEADER_LINE_HEIGHT (w) + add_y),
+               make_number (WINDOW_BOX_RIGHT_EDGE_X (w)
+                            - WINDOW_RIGHT_MARGIN_WIDTH (w)
+                            - WINDOW_RIGHT_FRINGE_WIDTH (w) + add_x),
+               make_number (WINDOW_BOTTOM_EDGE_Y (w)
+                            - WINDOW_MODE_LINE_HEIGHT (w) + add_y));
+}
+
+/* Test if the character at column X, row Y is within window W.
    If it is not, return ON_NOTHING;
-   if it is in the window's text area,
-      set *x and *y to its location relative to the upper left corner
-         of the window, and
-      return ON_TEXT;
+   if it is in the window's text area, return ON_TEXT;
    if it is on the window's modeline, return ON_MODE_LINE;
    if it is on the border between the window and its right sibling,
       return ON_VERTICAL_BORDER.
-   if it is on a scroll bar,
-      return ON_SCROLL_BAR.
+   if it is on a scroll bar, return ON_SCROLL_BAR.
    if it is on the window's top line, return ON_HEADER_LINE;
    if it is in left or right fringe of the window,
-      return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
-      to window-relative coordinates;
+      return ON_LEFT_FRINGE or ON_RIGHT_FRINGE;
    if it is in the marginal area to the left/right of the window,
-      return ON_LEFT_MARGIN or ON_RIGHT_MARGIN, and convert *X and *Y
-      to window-relative coordinates.
+      return ON_LEFT_MARGIN or ON_RIGHT_MARGIN.
 
    X and Y are frame relative pixel coordinates.  */
 
 static enum window_part
-coordinates_in_window (w, x, y)
-     register struct window *w;
-     register int *x, *y;
+coordinates_in_window (register struct window *w, int x, int y)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  int left_x, right_x, top_y, bottom_y;
   enum window_part part;
   int ux = FRAME_COLUMN_WIDTH (f);
-  int x0 = WINDOW_LEFT_EDGE_X (w);
-  int x1 = WINDOW_RIGHT_EDGE_X (w);
+  int left_x = WINDOW_LEFT_EDGE_X (w);
+  int right_x = WINDOW_RIGHT_EDGE_X (w);
+  int top_y = WINDOW_TOP_EDGE_Y (w);
+  int bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
   /* The width of the area where the vertical line can be dragged.
      (Between mode lines for instance.  */
   int grabbable_width = ux;
   int lmargin_width, rmargin_width, text_left, text_right;
 
+  /* Outside any interesting row or column?  */
+  if (y < top_y || y >= bottom_y || x < left_x || x >= right_x)
+    return ON_NOTHING;
+
+  /* On the mode line or header line?   */
+  if ((WINDOW_WANTS_MODELINE_P (w)
+       && y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w)
+       && (part = ON_MODE_LINE))
+      || (WINDOW_WANTS_HEADER_LINE_P (w)
+         && y < top_y + CURRENT_HEADER_LINE_HEIGHT (w)
+         && (part = ON_HEADER_LINE)))
+    {
+      /* If it's under/over the scroll bar portion of the mode/header
+        line, say it's on the vertical line.  That's to be able to
+        resize windows horizontally in case we're using toolkit scroll
+        bars.  Note: If scrollbars are on the left, the window that
+        must be eventually resized is that on the left of WINDOW.  */
+      if ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+          && !WINDOW_LEFTMOST_P (w)
+          && eabs (x - left_x) < grabbable_width)
+         || (!WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+             && !WINDOW_RIGHTMOST_P (w)
+             && eabs (x - right_x) < grabbable_width))
+       return ON_VERTICAL_BORDER;
+      else
+       return part;
+    }
+
   /* In what's below, we subtract 1 when computing right_x because we
      want the rightmost pixel, which is given by left_pixel+width-1.  */
   if (w->pseudo_window_p)
     {
       left_x = 0;
       right_x = WINDOW_TOTAL_WIDTH (w) - 1;
-      top_y = WINDOW_TOP_EDGE_Y (w);
-      bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
     }
   else
     {
       left_x = WINDOW_BOX_LEFT_EDGE_X (w);
       right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
-      top_y = WINDOW_TOP_EDGE_Y (w);
-      bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
-    }
-
-  /* Outside any interesting row?  */
-  if (*y < top_y || *y >= bottom_y)
-    return ON_NOTHING;
-
-  /* On the mode line or header line?  If it's near the start of
-     the mode or header line of window that's has a horizontal
-     sibling, say it's on the vertical line.  That's to be able
-     to resize windows horizontally in case we're using toolkit
-     scroll bars.  */
-
-  if (WINDOW_WANTS_MODELINE_P (w)
-      && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
-    {
-      part = ON_MODE_LINE;
-
-    header_vertical_border_check:
-      /* We're somewhere on the mode line.  We consider the place
-        between mode lines of horizontally adjacent mode lines
-        as the vertical border.  If scroll bars on the left,
-        return the right window.  */
-      if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
-         || WINDOW_RIGHTMOST_P (w))
-       {
-         if (!WINDOW_LEFTMOST_P (w) && eabs (*x - x0) < grabbable_width)
-           {
-             /* Convert X and Y to window relative coordinates.
-                Vertical border is at the left edge of window.  */
-             *x = max (0, *x - x0);
-             *y -= top_y;
-             return ON_VERTICAL_BORDER;
-           }
-       }
-      else
-       {
-         /* Make sure we're not at the rightmost position of a
-            mode-/header-line and there's yet another window on
-            the right.  (Bug#1372)  */
-         if ((WINDOW_RIGHTMOST_P (w) || *x < x1)
-             && eabs (*x - x1) < grabbable_width)
-           {
-             /* Convert X and Y to window relative coordinates.
-                Vertical border is at the right edge of window.  */
-             *x = min (x1, *x) - x0;
-             *y -= top_y;
-             return ON_VERTICAL_BORDER;
-           }
-       }
-
-      if (*x < x0 || *x >= x1)
-       return ON_NOTHING;
-
-      /* Convert X and Y to window relative coordinates.
-        Mode line starts at left edge of window.  */
-      *x -= x0;
-      *y -= top_y;
-      return part;
-    }
-
-  if (WINDOW_WANTS_HEADER_LINE_P (w)
-      && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
-    {
-      part = ON_HEADER_LINE;
-      goto header_vertical_border_check;
     }
 
-  if (*x < x0 || *x >= x1)
-    return ON_NOTHING;
-
   /* Outside any interesting column?  */
-  if (*x < left_x || *x > right_x)
-    {
-      *y -= top_y;
-      return ON_SCROLL_BAR;
-    }
+  if (x < left_x || x > right_x)
+    return ON_SCROLL_BAR;
 
   lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
   rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
@@ -844,81 +976,84 @@ coordinates_in_window (w, x, y)
       if (!w->pseudo_window_p
          && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
          && !WINDOW_RIGHTMOST_P (w)
-         && (eabs (*x - right_x) < grabbable_width))
-       {
-         /* Convert X and Y to window relative coordinates.
-            Vertical border is at the right edge of window.  */
-         *x = min (right_x, *x) - left_x;
-         *y -= top_y;
-         return ON_VERTICAL_BORDER;
-       }
-    }
-  else
-    {
-      /* Need to say "*x > right_x" rather than >=, since on character
-        terminals, the vertical line's x coordinate is right_x.  */
-      if (!w->pseudo_window_p
-         && !WINDOW_RIGHTMOST_P (w)
-         && *x > right_x - ux)
-       {
-         /* On the border on the right side of the window?  Assume that
-            this area begins at RIGHT_X minus a canonical char width.  */
-         *x = min (right_x, *x) - left_x;
-         *y -= top_y;
-         return ON_VERTICAL_BORDER;
-       }
+         && (eabs (x - right_x) < grabbable_width))
+       return ON_VERTICAL_BORDER;
     }
+  /* 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_RIGHTMOST_P (w)
+          && x > right_x - ux)
+    return ON_VERTICAL_BORDER;
 
-  if (*x < text_left)
+  if (x < text_left)
     {
       if (lmargin_width > 0
          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-             ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
-             : (*x < left_x + lmargin_width)))
-       {
-         *x -= left_x;
-         if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
-           *x -= WINDOW_LEFT_FRINGE_WIDTH (w);
-         *y -= top_y;
-         return ON_LEFT_MARGIN;
-       }
+             ? (x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
+             : (x < left_x + lmargin_width)))
+       return ON_LEFT_MARGIN;
 
-      /* Convert X and Y to window-relative pixel coordinates.  */
-      *x -= left_x;
-      *y -= top_y;
       return ON_LEFT_FRINGE;
     }
 
-  if (*x >= text_right)
+  if (x >= text_right)
     {
       if (rmargin_width > 0
          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-             ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
-             : (*x >= right_x - rmargin_width)))
-       {
-         *x -= right_x - rmargin_width;
-         if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
-           *x += WINDOW_RIGHT_FRINGE_WIDTH (w);
-         *y -= top_y;
-         return ON_RIGHT_MARGIN;
-       }
+             ? (x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
+             : (x >= right_x - rmargin_width)))
+       return ON_RIGHT_MARGIN;
 
-      /* Convert X and Y to window-relative pixel coordinates.  */
-      *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
-      *y -= top_y;
       return ON_RIGHT_FRINGE;
     }
 
   /* Everything special ruled out - must be on text area */
-  *x -= text_left;
-  *y -= top_y;
   return ON_TEXT;
 }
 
+/* Take X is the frame-relative pixel x-coordinate, and return the
+   x-coordinate relative to part PART of window W. */
+int
+window_relative_x_coord (struct window *w, enum window_part part, int x)
+{
+  int left_x = (w->pseudo_window_p) ? 0 : WINDOW_BOX_LEFT_EDGE_X (w);
+
+  switch (part)
+    {
+    case ON_TEXT:
+      return x - window_box_left (w, TEXT_AREA);
+
+    case ON_LEFT_FRINGE:
+      return x - left_x;
+
+    case ON_RIGHT_FRINGE:
+      return x - left_x - WINDOW_LEFT_FRINGE_WIDTH (w);
+
+    case ON_LEFT_MARGIN:
+      return (x - left_x
+             - ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+                ? WINDOW_LEFT_FRINGE_WIDTH (w) : 0));
+
+    case ON_RIGHT_MARGIN:
+      return (x + 1
+             - ((w->pseudo_window_p)
+                ? WINDOW_TOTAL_WIDTH (w)
+                : WINDOW_BOX_RIGHT_EDGE_X (w))
+             + window_box_width (w, RIGHT_MARGIN_AREA)
+             + ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+                ? WINDOW_RIGHT_FRINGE_WIDTH (w) : 0));
+    }
+
+  /* ON_SCROLL_BAR, ON_NOTHING, and ON_VERTICAL_BORDER:  */
+  return 0;
+}
+
 
 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
        Scoordinates_in_window_p, 2, 2, 0,
        doc: /* Return non-nil if COORDINATES are in WINDOW.
+WINDOW must be a live window.
 COORDINATES is a cons of the form (X . Y), X and Y being distances
 measured in characters from the upper-left corner of the frame.
 \(0 . 0) denotes the character in the upper left corner of the
@@ -933,15 +1068,14 @@ If they are on the border between WINDOW and its right sibling,
   `vertical-line' is returned.
 If they are in the windows's left or right marginal areas, `left-margin'\n\
   or `right-margin' is returned.  */)
-     (coordinates, window)
-     register Lisp_Object coordinates, window;
+  (register Lisp_Object coordinates, Lisp_Object window)
 {
   struct window *w;
   struct frame *f;
   int x, y;
   Lisp_Object lx, ly;
 
-  CHECK_WINDOW (window);
+  CHECK_LIVE_WINDOW (window);
   w = XWINDOW (window);
   f = XFRAME (w->frame);
   CHECK_CONS (coordinates);
@@ -952,14 +1086,16 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
   x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
   y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
 
-  switch (coordinates_in_window (w, &x, &y))
+  switch (coordinates_in_window (w, x, y))
     {
     case ON_NOTHING:
       return Qnil;
 
     case ON_TEXT:
-      /* X and Y are now window relative pixel coordinates.  Convert
-        them to canonical char units before returning them.  */
+      /* Convert X and Y to window relative pixel coordinates, and
+        return the canonical char units.  */
+      x -= window_box_left (w, TEXT_AREA);
+      y -= WINDOW_TOP_EDGE_Y (w);
       return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
                    FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
 
@@ -1006,14 +1142,12 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
 struct check_window_data
 {
   Lisp_Object *window;
-  int *x, *y;
+  int x, y;
   enum window_part *part;
 };
 
 static int
-check_window_containing (w, user_data)
-     struct window *w;
-     void *user_data;
+check_window_containing (struct window *w, void *user_data)
 {
   struct check_window_data *cw = (struct check_window_data *) user_data;
   enum window_part found;
@@ -1035,8 +1169,7 @@ check_window_containing (w, user_data)
    return it as a Lisp_Object.
 
    If X, Y is on one of the window's special `window_part' elements,
-   set *PART to the id of that element, and return X and Y converted
-   to window relative coordinates in WX and WY.
+   set *PART to the id of that element.
 
    If there is no window under X, Y return nil and leave *PART
    unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.
@@ -1051,12 +1184,8 @@ check_window_containing (w, user_data)
    case.  */
 
 Lisp_Object
-window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
-     struct frame *f;
-     int x, y;
-     enum window_part *part;
-     int *wx, *wy;
-     int tool_bar_p;
+window_from_coordinates (struct frame *f, int x, int y,
+                        enum window_part *part, int tool_bar_p)
 {
   Lisp_Object window;
   struct check_window_data cw;
@@ -1066,7 +1195,7 @@ window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
     part = &dummy;
 
   window = Qnil;
-  cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
+  cw.window = &window, cw.x = x, cw.y = y; cw.part = part;
   foreach_window (f, check_window_containing, &cw);
 
   /* If not found above, see if it's in the tool bar window, if a tool
@@ -1075,26 +1204,22 @@ window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
       && tool_bar_p
       && WINDOWP (f->tool_bar_window)
       && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
-      && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
+      && (coordinates_in_window (XWINDOW (f->tool_bar_window), x, y)
          != ON_NOTHING))
     {
       *part = ON_TEXT;
       window = f->tool_bar_window;
     }
 
-  if (wx) *wx = x;
-  if (wy) *wy = y;
-
   return window;
 }
 
 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
        doc: /* Return window containing coordinates X and Y on FRAME.
-If omitted, FRAME defaults to the currently selected frame.
+FRAME must be a live frame and defaults to the selected one.
 The top left corner of the frame is considered to be row 0,
 column 0.  */)
-     (x, y, frame)
-     Lisp_Object x, y, frame;
+  (Lisp_Object x, Lisp_Object y, Lisp_Object frame)
 {
   struct frame *f;
 
@@ -1112,12 +1237,12 @@ column 0.  */)
                                   + FRAME_INTERNAL_BORDER_WIDTH (f)),
                                  (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
                                   + FRAME_INTERNAL_BORDER_WIDTH (f)),
-                                 0, 0, 0, 0);
+                                 0, 0);
 }
 
 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
        doc: /* Return current value of point in WINDOW.
-WINDOW defaults to the selected window.
+WINDOW must be a live window and defaults to the selected one.
 
 For a nonselected window, this is the value point would have
 if that window were selected.
@@ -1127,8 +1252,7 @@ is also currently selected, the value returned is the same as (point).
 It would be more strictly correct to return the `top-level' value
 of point, outside of any save-excursion forms.
 But that is hard to define.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   register struct window *w = decode_window (window);
 
@@ -1140,10 +1264,9 @@ But that is hard to define.  */)
 
 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
        doc: /* Return position at which display currently starts in WINDOW.
-WINDOW defaults to the selected window.
+WINDOW must be a live window and defaults to the selected one.
 This is updated by redisplay or by calling `set-window-start'.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   return Fmarker_position (decode_window (window)->start);
 }
@@ -1161,16 +1284,15 @@ have been if redisplay had finished, do this:
 
 DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
        doc: /* Return position at which display currently ends in WINDOW.
-WINDOW defaults to the selected window.
+WINDOW must be a live window and defaults to the selected one.
 This is updated by redisplay, when it runs to completion.
 Simply changing the buffer text or setting `window-start'
 does not update this value.
-Return nil if there is no recorded value.  \(This can happen if the
+Return nil if there is no recorded value.  (This can happen if the
 last redisplay of WINDOW was preempted, and did not finish.)
 If UPDATE is non-nil, compute the up-to-date position
 if it isn't already recorded.  */)
-     (window, update)
-     Lisp_Object window, update;
+  (Lisp_Object window, Lisp_Object update)
 {
   Lisp_Object value;
   struct window *w = decode_window (window);
@@ -1199,6 +1321,7 @@ if it isn't already recorded.  */)
       struct text_pos startp;
       struct it it;
       struct buffer *old_buffer = NULL;
+      void *itdata = NULL;
 
       /* Cannot use Fvertical_motion because that function doesn't
         cope with variable-height lines.  */
@@ -1220,11 +1343,13 @@ if it isn't already recorded.  */)
       else
        SET_TEXT_POS_FROM_MARKER (startp, w->start);
 
+      itdata = bidi_shelve_cache ();
       start_display (&it, w, startp);
       move_it_vertically (&it, window_box_height (w));
       if (it.current_y < it.last_visible_y)
        move_it_past_eol (&it);
       value = make_number (IT_CHARPOS (it));
+      bidi_unshelve_cache (itdata, 0);
 
       if (old_buffer)
        set_buffer_internal (old_buffer);
@@ -1238,8 +1363,7 @@ if it isn't already recorded.  */)
 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
        doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
 Return POS.  */)
-     (window, pos)
-     Lisp_Object window, pos;
+  (Lisp_Object window, Lisp_Object pos)
 {
   register struct window *w = decode_window (window);
 
@@ -1260,21 +1384,20 @@ Return POS.  */)
 
 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
        doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
-WINDOW defaults to the selected window.  Return POS.
+If WINDOW is nil, the selected window is used.  Return POS.
 Optional third arg NOFORCE non-nil inhibits next redisplay from
 overriding motion of point in order to display at this exact start.  */)
-     (window, pos, noforce)
-     Lisp_Object window, pos, noforce;
+  (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce)
 {
   register struct window *w = decode_window (window);
 
   CHECK_NUMBER_COERCE_MARKER (pos);
   set_marker_restricted (w->start, pos, w->buffer);
   /* this is not right, but much easier than doing what is right. */
-  w->start_at_line_beg = Qnil;
+  w->start_at_line_beg = 0;
   if (NILP (noforce))
-    w->force_start = Qt;
-  w->update_mode_line = Qt;
+    w->force_start = 1;
+  w->update_mode_line = 1;
   XSETFASTINT (w->last_modified, 0);
   XSETFASTINT (w->last_overlay_modified, 0);
   if (!EQ (window, selected_window))
@@ -1283,12 +1406,186 @@ overriding motion of point in order to display at this exact start.  */)
   return pos;
 }
 
+DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
+       Spos_visible_in_window_p, 0, 3, 0,
+       doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
+Return nil if that position is scrolled vertically out of view.
+If a character is only partially visible, nil is returned, unless the
+optional argument PARTIALLY is non-nil.
+If POS is only out of view because of horizontal scrolling, return non-nil.
+If POS is t, it specifies the position of the last visible glyph in WINDOW.
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.
 
-DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
-       0, 1, 0,
-       doc: /* Return non-nil when WINDOW is dedicated to its buffer.
-More precisely, return the value assigned by the last call of
-`set-window-dedicated-p' for WINDOW.  Return nil if that function was
+If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
+return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
+where X and Y are the pixel coordinates relative to the top left corner
+of the window.  The remaining elements are omitted if the character after
+POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
+off-window at the top and bottom of the row, ROWH is the height of the
+display row, and VPOS is the row number (0-based) containing POS.  */)
+  (Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
+{
+  register struct window *w;
+  register EMACS_INT posint;
+  register struct buffer *buf;
+  struct text_pos top;
+  Lisp_Object in_window = Qnil;
+  int rtop, rbot, rowh, vpos, fully_p = 1;
+  int x, y;
+
+  w = decode_window (window);
+  buf = XBUFFER (w->buffer);
+  SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+  if (EQ (pos, Qt))
+    posint = -1;
+  else if (!NILP (pos))
+    {
+      CHECK_NUMBER_COERCE_MARKER (pos);
+      posint = XINT (pos);
+    }
+  else if (w == XWINDOW (selected_window))
+    posint = PT;
+  else
+    posint = XMARKER (w->pointm)->charpos;
+
+  /* If position is above window start or outside buffer boundaries,
+     or if window start is out of range, position is not visible.  */
+  if ((EQ (pos, Qt)
+       || (posint >= CHARPOS (top) && posint <= BUF_ZV (buf)))
+      && CHARPOS (top) >= BUF_BEGV (buf)
+      && CHARPOS (top) <= BUF_ZV (buf)
+      && pos_visible_p (w, posint, &x, &y, &rtop, &rbot, &rowh, &vpos)
+      && (fully_p = !rtop && !rbot, (!NILP (partially) || fully_p)))
+    in_window = Qt;
+
+  if (!NILP (in_window) && !NILP (partially))
+    {
+      Lisp_Object part = Qnil;
+      if (!fully_p)
+       part = list4 (make_number (rtop), make_number (rbot),
+                       make_number (rowh), make_number (vpos));
+      in_window = Fcons (make_number (x),
+                        Fcons (make_number (y), part));
+    }
+
+  return in_window;
+}
+
+DEFUN ("window-line-height", Fwindow_line_height,
+       Swindow_line_height, 0, 2, 0,
+       doc: /* Return height in pixels of text line LINE in window WINDOW.
+WINDOW defaults to the selected window.
+
+Return height of current line if LINE is omitted or nil.  Return height of
+header or mode line if LINE is `header-line' or `mode-line'.
+Otherwise, LINE is a text line number starting from 0.  A negative number
+counts from the end of the window.
+
+Value is a list (HEIGHT VPOS YPOS OFFBOT), where HEIGHT is the height
+in pixels of the visible part of the line, VPOS and YPOS are the
+vertical position in lines and pixels of the line, relative to the top
+of the first text line, and OFFBOT is the number of off-window pixels at
+the bottom of the text line.  If there are off-window pixels at the top
+of the (first) text line, YPOS is negative.
+
+Return nil if window display is not up-to-date.  In that case, use
+`pos-visible-in-window-p' to obtain the information.  */)
+  (Lisp_Object line, Lisp_Object window)
+{
+  register struct window *w;
+  register struct buffer *b;
+  struct glyph_row *row, *end_row;
+  int max_y, crop, i;
+  EMACS_INT n;
+
+  w = decode_window (window);
+
+  if (noninteractive || w->pseudo_window_p)
+    return Qnil;
+
+  CHECK_BUFFER (w->buffer);
+  b = XBUFFER (w->buffer);
+
+  /* Fail if current matrix is not up-to-date.  */
+  if (NILP (w->window_end_valid)
+      || current_buffer->clip_changed
+      || current_buffer->prevent_redisplay_optimizations_p
+      || XFASTINT (w->last_modified) < BUF_MODIFF (b)
+      || XFASTINT (w->last_overlay_modified) < BUF_OVERLAY_MODIFF (b))
+    return Qnil;
+
+  if (NILP (line))
+    {
+      i = w->cursor.vpos;
+      if (i < 0 || i >= w->current_matrix->nrows
+         || (row = MATRIX_ROW (w->current_matrix, i), !row->enabled_p))
+       return Qnil;
+      max_y = window_text_bottom_y (w);
+      goto found_row;
+    }
+
+  if (EQ (line, Qheader_line))
+    {
+      if (!WINDOW_WANTS_HEADER_LINE_P (w))
+       return Qnil;
+      row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
+      if (!row->enabled_p)
+       return Qnil;
+      return list4 (make_number (row->height),
+                   make_number (0), make_number (0),
+                   make_number (0));
+    }
+
+  if (EQ (line, Qmode_line))
+    {
+      row = MATRIX_MODE_LINE_ROW (w->current_matrix);
+      if (!row->enabled_p)
+       return Qnil;
+      return list4 (make_number (row->height),
+                   make_number (0), /* not accurate */
+                   make_number (WINDOW_HEADER_LINE_HEIGHT (w)
+                                + window_text_bottom_y (w)),
+                   make_number (0));
+    }
+
+  CHECK_NUMBER (line);
+  n = XINT (line);
+
+  row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+  max_y = window_text_bottom_y (w);
+  i = 0;
+
+  while ((n < 0 || i < n)
+        && row <= end_row && row->enabled_p
+        && row->y + row->height < max_y)
+    row++, i++;
+
+  if (row > end_row || !row->enabled_p)
+    return Qnil;
+
+  if (++n < 0)
+    {
+      if (-n > i)
+       return Qnil;
+      row += n;
+      i += n;
+    }
+
+ found_row:
+  crop = max (0, (row->y + row->height) - max_y);
+  return list4 (make_number (row->height + min (0, row->y) - crop),
+               make_number (i),
+               make_number (row->y),
+               make_number (crop));
+}
+
+DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
+       0, 1, 0,
+       doc: /* Return non-nil when WINDOW is dedicated to its buffer.
+More precisely, return the value assigned by the last call of
+`set-window-dedicated-p' for WINDOW.  Return nil if that function was
 never called with WINDOW as its argument, or the value set by that
 function was internally reset since its last call.  WINDOW defaults to
 the selected window.
@@ -1302,8 +1599,7 @@ from displaying another buffer in it.  `get-lru-window' and
 Functions like `set-window-buffer' may change the buffer displayed by a
 window, unless that window is "strongly" dedicated to its buffer, that
 is the value returned by `window-dedicated-p' is t.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   return decode_window (window)->dedicated;
 }
@@ -1311,24 +1607,23 @@ is the value returned by `window-dedicated-p' is t.  */)
 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
        Sset_window_dedicated_p, 2, 2, 0,
        doc: /* Mark WINDOW as dedicated according to FLAG.
-WINDOW defaults to the selected window.  FLAG non-nil means mark WINDOW
-as dedicated to its buffer.  FLAG nil means mark WINDOW as non-dedicated.
-Return FLAG.
+WINDOW must be a live window and defaults to the selected one.  FLAG
+non-nil means mark WINDOW as dedicated to its buffer.  FLAG nil means
+mark WINDOW as non-dedicated.  Return FLAG.
 
 When a window is dedicated to its buffer, `display-buffer' will refrain
 from displaying another buffer in it.  `get-lru-window' and
 `get-largest-window' treat dedicated windows specially.
-`delete-windows-on', `replace-buffer-in-windows', `quit-window' and
-`kill-buffer' can delete a dedicated window and the containing
-frame.
+`delete-windows-on', `replace-buffer-in-windows', `quit-window',
+`quit-restore-window' and `kill-buffer' can delete a dedicated window
+and the containing frame.
 
 As a special case, if FLAG is t, mark WINDOW as "strongly" dedicated to
 its buffer.  Functions like `set-window-buffer' may change the buffer
 displayed by a window, unless that window is strongly dedicated to its
 buffer.  If and when `set-window-buffer' displays another buffer in a
-window, it also makes sure that the window is not marked as dedicated.  */)
-     (window, flag)
-     Lisp_Object window, flag;
+window, it also makes sure that the window is no more dedicated.  */)
+  (Lisp_Object window, Lisp_Object flag)
 {
   register struct window *w = decode_window (window);
 
@@ -1336,28 +1631,70 @@ window, it also makes sure that the window is not marked as dedicated.  */)
   return w->dedicated;
 }
 
+DEFUN ("window-prev-buffers", Fwindow_prev_buffers, Swindow_prev_buffers,
+       0, 1, 0,
+       doc:  /* Return buffers previously shown in WINDOW.
+WINDOW must be a live window and defaults to the selected one.
+
+The return value is a list of elements (BUFFER WINDOW-START POS),
+where BUFFER is a buffer, WINDOW-START is the start position of the
+window for that buffer, and POS is a window-specific point value.  */)
+  (Lisp_Object window)
+{
+  return decode_window (window)->prev_buffers;
+}
+
+DEFUN ("set-window-prev-buffers", Fset_window_prev_buffers,
+       Sset_window_prev_buffers, 2, 2, 0,
+       doc: /* Set WINDOW's previous buffers to PREV-BUFFERS.
+WINDOW must be a live window and defaults to the selected one.
+
+PREV-BUFFERS should be a list of elements (BUFFER WINDOW-START POS),
+where BUFFER is a buffer, WINDOW-START is the start position of the
+window for that buffer, and POS is a window-specific point value.  */)
+     (Lisp_Object window, Lisp_Object prev_buffers)
+{
+  return decode_window (window)->prev_buffers = prev_buffers;
+}
+
+DEFUN ("window-next-buffers", Fwindow_next_buffers, Swindow_next_buffers,
+       0, 1, 0,
+       doc:  /* Return list of buffers recently re-shown in WINDOW.
+WINDOW must be a live window and defaults to the selected one.  */)
+     (Lisp_Object window)
+{
+  return decode_window (window)->next_buffers;
+}
+
+DEFUN ("set-window-next-buffers", Fset_window_next_buffers,
+       Sset_window_next_buffers, 2, 2, 0,
+       doc: /* Set WINDOW's next buffers to NEXT-BUFFERS.
+WINDOW must be a live window and defaults to the selected one.
+NEXT-BUFFERS should be a list of buffers.  */)
+     (Lisp_Object window, Lisp_Object next_buffers)
+{
+  return decode_window (window)->next_buffers = next_buffers;
+}
 
 DEFUN ("window-parameters", Fwindow_parameters, Swindow_parameters,
        0, 1, 0,
        doc: /* Return the parameters of WINDOW and their values.
 WINDOW defaults to the selected window.  The return value is a list of
-elements of the form (PARAMETER . VALUE). */)
-     (window)
-     Lisp_Object window;
+elements of the form (PARAMETER . VALUE).  */)
+  (Lisp_Object window)
 {
-  return Fcopy_alist (decode_window (window)->window_parameters);
+  return Fcopy_alist (decode_any_window (window)->window_parameters);
 }
 
 DEFUN ("window-parameter", Fwindow_parameter, Swindow_parameter,
        2, 2, 0,
        doc:  /* Return WINDOW's value for PARAMETER.
 WINDOW defaults to the selected window.  */)
-     (window, parameter)
-     Lisp_Object window, parameter;
+  (Lisp_Object window, Lisp_Object parameter)
 {
   Lisp_Object result;
 
-  result = Fassq (parameter, decode_window (window)->window_parameters);
+  result = Fassq (parameter, decode_any_window (window)->window_parameters);
   return CDR_SAFE (result);
 }
 
@@ -1365,10 +1702,9 @@ DEFUN ("set-window-parameter", Fset_window_parameter,
        Sset_window_parameter, 3, 3, 0,
        doc: /* Set WINDOW's value of PARAMETER to VALUE.
 WINDOW defaults to the selected window.  Return VALUE.  */)
-     (window, parameter, value)
-     Lisp_Object window, parameter, value;
+  (Lisp_Object window, Lisp_Object parameter, Lisp_Object value)
 {
-  register struct window *w = decode_window (window);
+  register struct window *w = decode_any_window (window);
   Lisp_Object old_alist_elt;
 
   old_alist_elt = Fassq (parameter, w->window_parameters);
@@ -1379,13 +1715,11 @@ WINDOW defaults to the selected window.  Return VALUE.  */)
   return value;
 }
 
-
 DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
        0, 1, 0,
        doc: /* Return the display-table that WINDOW is using.
 WINDOW defaults to the selected window.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   return decode_window (window)->display_table;
 }
@@ -1396,8 +1730,7 @@ WINDOW defaults to the selected window.  */)
    return 0.  */
 
 struct Lisp_Char_Table *
-window_display_table (w)
-     struct window *w;
+window_display_table (struct window *w)
 {
   struct Lisp_Char_Table *dp = NULL;
 
@@ -1407,8 +1740,8 @@ window_display_table (w)
     {
       struct buffer *b = XBUFFER (w->buffer);
 
-      if (DISP_TABLE_P (b->display_table))
-       dp = XCHAR_TABLE (b->display_table);
+      if (DISP_TABLE_P (BVAR (b, display_table)))
+       dp = XCHAR_TABLE (BVAR (b, display_table));
       else if (DISP_TABLE_P (Vstandard_display_table))
        dp = XCHAR_TABLE (Vstandard_display_table);
     }
@@ -1418,8 +1751,7 @@ window_display_table (w)
 
 DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_display_table, 2, 2, 0,
        doc: /* Set WINDOW's display-table to TABLE.  */)
-     (window, table)
-     register Lisp_Object window, table;
+  (register Lisp_Object window, Lisp_Object table)
 {
   register struct window *w;
 
@@ -1428,11 +1760,10 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
   return table;
 }
 \f
-/* Record info on buffer window w is displaying
+/* Record info on buffer window W is displaying
    when it is about to cease to display that buffer.  */
 static void
-unshow_buffer (w)
-     register struct window *w;
+unshow_buffer (register struct window *w)
 {
   Lisp_Object buf;
   struct buffer *b;
@@ -1462,9 +1793,9 @@ unshow_buffer (w)
      So don't clobber point in that buffer.  */
   if (! EQ (buf, XWINDOW (selected_window)->buffer)
       /* This line helps to fix Horsley's testbug.el bug.  */
-      && !(WINDOWP (b->last_selected_window)
-          && w != XWINDOW (b->last_selected_window)
-          && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
+      && !(WINDOWP (BVAR (b, last_selected_window))
+          && w != XWINDOW (BVAR (b, last_selected_window))
+          && EQ (buf, XWINDOW (BVAR (b, last_selected_window))->buffer)))
     temp_set_point_both (b,
                         clip_to_bounds (BUF_BEGV (b),
                                         XMARKER (w->pointm)->charpos,
@@ -1473,321 +1804,175 @@ unshow_buffer (w)
                                         marker_byte_position (w->pointm),
                                         BUF_ZV_BYTE (b)));
 
-  if (WINDOWP (b->last_selected_window)
-      && w == XWINDOW (b->last_selected_window))
-    b->last_selected_window = Qnil;
+  if (WINDOWP (BVAR (b, last_selected_window))
+      && w == XWINDOW (BVAR (b, last_selected_window)))
+    BVAR (b, last_selected_window) = Qnil;
 }
 
-/* Put replacement into the window structure in place of old. */
+/* Put NEW into the window structure in place of OLD.  SETFLAG zero
+   means change window structure only.  Otherwise store geometry and
+   other settings as well.  */
 static void
-replace_window (old, replacement)
-     Lisp_Object old, replacement;
+replace_window (Lisp_Object old, Lisp_Object new, int setflag)
 {
   register Lisp_Object tem;
-  register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
-
-  /* If OLD is its frame's root_window, then replacement is the new
-     root_window for that frame.  */
+  register struct window *o = XWINDOW (old), *n = XWINDOW (new);
 
+  /* If OLD is its frame's root window, then NEW is the new
+     root window for that frame.  */
   if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
-    FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
-
-  p->left_col = o->left_col;
-  p->top_line = o->top_line;
-  p->total_cols = o->total_cols;
-  p->total_lines = o->total_lines;
-  p->desired_matrix = p->current_matrix = 0;
-  p->vscroll = 0;
-  bzero (&p->cursor, sizeof (p->cursor));
-  bzero (&p->last_cursor, sizeof (p->last_cursor));
-  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
-  p->phys_cursor_type = -1;
-  p->phys_cursor_width = -1;
-  p->must_be_updated_p = 0;
-  p->pseudo_window_p = 0;
-  XSETFASTINT (p->window_end_vpos, 0);
-  XSETFASTINT (p->window_end_pos, 0);
-  p->window_end_valid = Qnil;
-  p->frozen_window_start_p = 0;
-  p->orig_top_line = p->orig_total_lines = Qnil;
-
-  p->next = tem = o->next;
+    FRAME_ROOT_WINDOW (XFRAME (o->frame)) = new;
+
+  if (setflag)
+    {
+      n->left_col = o->left_col;
+      n->top_line = o->top_line;
+      n->total_cols = o->total_cols;
+      n->total_lines = o->total_lines;
+      n->normal_cols = o->normal_cols;
+      o->normal_cols = make_float (1.0);
+      n->normal_lines = o->normal_lines;
+      o->normal_lines = make_float (1.0);
+      n->desired_matrix = n->current_matrix = 0;
+      n->vscroll = 0;
+      memset (&n->cursor, 0, sizeof (n->cursor));
+      memset (&n->last_cursor, 0, sizeof (n->last_cursor));
+      memset (&n->phys_cursor, 0, sizeof (n->phys_cursor));
+      n->phys_cursor_type = -1;
+      n->phys_cursor_width = -1;
+      n->must_be_updated_p = 0;
+      n->pseudo_window_p = 0;
+      XSETFASTINT (n->window_end_vpos, 0);
+      XSETFASTINT (n->window_end_pos, 0);
+      n->window_end_valid = Qnil;
+      n->frozen_window_start_p = 0;
+    }
+
+  n->next = tem = o->next;
   if (!NILP (tem))
-    XWINDOW (tem)->prev = replacement;
+    XWINDOW (tem)->prev = new;
 
-  p->prev = tem = o->prev;
+  n->prev = tem = o->prev;
   if (!NILP (tem))
-    XWINDOW (tem)->next = replacement;
+    XWINDOW (tem)->next = new;
 
-  p->parent = tem = o->parent;
+  n->parent = tem = o->parent;
   if (!NILP (tem))
     {
       if (EQ (XWINDOW (tem)->vchild, old))
-       XWINDOW (tem)->vchild = replacement;
+       XWINDOW (tem)->vchild = new;
       if (EQ (XWINDOW (tem)->hchild, old))
-       XWINDOW (tem)->hchild = replacement;
+       XWINDOW (tem)->hchild = new;
     }
-
-/*** Here, if replacement is a vertical combination
-and so is its new parent, we should make replacement's
-children be children of that parent instead.  ***/
 }
 
-DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
-       doc: /* Remove WINDOW from its frame.
-WINDOW defaults to the selected window.  Return nil.
-Signal an error when WINDOW is the only window on its frame.  */)
-     (window)
-     register Lisp_Object window;
+/* If window WINDOW and its parent window are iso-combined, merge
+   WINDOW's children into those of its parent window and mark WINDOW as
+   deleted.  */
+
+static void
+recombine_windows (Lisp_Object window)
 {
-  struct frame *f;
-  if (NILP (window))
-    window = selected_window;
-  else
-    CHECK_LIVE_WINDOW (window);
+  struct window *w, *p, *c;
+  Lisp_Object parent, child;
+  int horflag;
 
-  f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
-  delete_window (window);
+  w = XWINDOW (window);
+  parent = w->parent;
+  if (!NILP (parent) && NILP (w->combination_limit))
+    {
+      p = XWINDOW (parent);
+      if (((!NILP (p->vchild) && !NILP (w->vchild))
+          || (!NILP (p->hchild) && !NILP (w->hchild))))
+       /* WINDOW and PARENT are both either a vertical or a horizontal
+          combination.  */
+       {
+         horflag = NILP (w->vchild);
+         child = horflag ? w->hchild : w->vchild;
+         c = XWINDOW (child);
 
-  run_window_configuration_change_hook (f);
+         /* Splice WINDOW's children into its parent's children and
+            assign new normal sizes.  */
+         if (NILP (w->prev))
+           if (horflag)
+             p->hchild = child;
+           else
+             p->vchild = child;
+         else
+           {
+             c->prev = w->prev;
+             XWINDOW (w->prev)->next = child;
+           }
 
-  return Qnil;
-}
+         while (c)
+           {
+             c->parent = parent;
 
-void
-delete_window (window)
-     register Lisp_Object window;
-{
-  register Lisp_Object tem, parent, sib;
-  register struct window *p;
-  register struct window *par;
-  struct frame *f;
+             if (horflag)
+               c->normal_cols
+                 = make_float (XFLOATINT (c->total_cols)
+                               / XFLOATINT (p->total_cols));
+             else
+               c->normal_lines
+                 = make_float (XFLOATINT (c->total_lines)
+                               / XFLOATINT (p->total_lines));
 
-  /* Because this function is called by other C code on non-leaf
-     windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
-     so we can't decode_window here.  */
-  CHECK_WINDOW (window);
-  p = XWINDOW (window);
+             if (NILP (c->next))
+               {
+                 if (!NILP (w->next))
+                   {
+                     c->next = w->next;
+                     XWINDOW (c->next)->prev = child;
+                   }
 
-  /* It's a no-op to delete an already-deleted window.  */
-  if (NILP (p->buffer)
-      && NILP (p->hchild)
-      && NILP (p->vchild))
-    return;
+                 c = 0;
+               }
+             else
+               {
+                 child = c->next;
+                 c = XWINDOW (child);
+               }
+           }
 
-  parent = p->parent;
-  if (NILP (parent))
-    error ("Attempt to delete minibuffer or sole ordinary window");
-  par = XWINDOW (parent);
+         /* WINDOW can be deleted now.  */
+         w->vchild = w->hchild = Qnil;
+       }
+    }
+}
 
-  windows_or_buffers_changed++;
-  Vwindow_list = Qnil;
-  f = XFRAME (WINDOW_FRAME (p));
-  FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+/* If WINDOW can be deleted, delete it.  */
+static void
+delete_deletable_window (Lisp_Object window)
+{
+  if (!NILP (call1 (Qwindow_deletable_p, window)))
+    call1 (Qdelete_window, window);
+}
+\f
+/***********************************************************************
+                            Window List
+ ***********************************************************************/
 
-  /* Are we trying to delete any frame's selected window?  */
-  {
-    Lisp_Object swindow, pwindow;
+/* Add window W to *USER_DATA.  USER_DATA is actually a Lisp_Object
+   pointer.  This is a callback function for foreach_window, used in
+   the window_list function.  */
 
-    /* See if the frame's selected window is either WINDOW
-       or any subwindow of it, by finding all that window's parents
-       and comparing each one with WINDOW.  */
-    swindow = FRAME_SELECTED_WINDOW (f);
+static int
+add_window_to_list (struct window *w, void *user_data)
+{
+  Lisp_Object *list = (Lisp_Object *) user_data;
+  Lisp_Object window;
+  XSETWINDOW (window, w);
+  *list = Fcons (window, *list);
+  return 1;
+}
 
-    while (1)
-      {
-       pwindow = swindow;
-       while (!NILP (pwindow))
-         {
-           if (EQ (window, pwindow))
-             break;
-           pwindow = XWINDOW (pwindow)->parent;
-         }
 
-       /* If the window being deleted is not a parent of SWINDOW,
-          then SWINDOW is ok as the new selected window.  */
-       if (!EQ (window, pwindow))
-         break;
-       /* Otherwise, try another window for SWINDOW.  */
-       swindow = Fnext_window (swindow, Qlambda, Qnil);
-
-       /* If we get back to the frame's selected window,
-          it means there was no acceptable alternative,
-          so we cannot delete.  */
-       if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
-         error ("Cannot delete window");
-      }
-
-    /* If we need to change SWINDOW, do it.  */
-    if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
-      {
-       /* If we're about to delete the selected window on the
-          selected frame, then we should use Fselect_window to select
-          the new window.  On the other hand, if we're about to
-          delete the selected window on any other frame, we shouldn't do
-          anything but set the frame's selected_window slot.  */
-       if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
-         Fselect_window (swindow, Qnil);
-       else
-         FRAME_SELECTED_WINDOW (f) = swindow;
-      }
-  }
-
-  /* Now we know we can delete this one.  */
-  window_deletion_count++;
-
-  tem = p->buffer;
-  /* tem is null for dummy parent windows
-     (which have inferiors but not any contents themselves) */
-  if (!NILP (tem))
-    {
-      unshow_buffer (p);
-      unchain_marker (XMARKER (p->pointm));
-      unchain_marker (XMARKER (p->start));
-    }
-
-  /* Free window glyph matrices.  It is sure that they are allocated
-     again when ADJUST_GLYPHS is called.  Block input so that expose
-     events and other events that access glyph matrices are not
-     processed while we are changing them.  */
-  BLOCK_INPUT;
-  free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
-
-  tem = p->next;
-  if (!NILP (tem))
-    XWINDOW (tem)->prev = p->prev;
-
-  tem = p->prev;
-  if (!NILP (tem))
-    XWINDOW (tem)->next = p->next;
-
-  if (EQ (window, par->hchild))
-    par->hchild = p->next;
-  if (EQ (window, par->vchild))
-    par->vchild = p->next;
-
-  /* Find one of our siblings to give our space to.  */
-  sib = p->prev;
-  if (NILP (sib))
-    {
-      /* If p gives its space to its next sibling, that sibling needs
-        to have its top/left side pulled back to where p's is.
-        set_window_{height,width} will re-position the sibling's
-        children.  */
-      sib = p->next;
-      XWINDOW (sib)->top_line = p->top_line;
-      XWINDOW (sib)->left_col = p->left_col;
-    }
-
-  /* Stretch that sibling.  */
-  if (!NILP (par->vchild))
-    set_window_height (sib,
-                      XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT (p->total_lines),
-                      1);
-  if (!NILP (par->hchild))
-    set_window_width (sib,
-                     XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT (p->total_cols),
-                     1);
-
-  /* If parent now has only one child,
-     put the child into the parent's place.  */
-  tem = par->hchild;
-  if (NILP (tem))
-    tem = par->vchild;
-  if (NILP (XWINDOW (tem)->next)) {
-    replace_window (parent, tem);
-    par = XWINDOW (tem);
-  }
-
-  /* Since we may be deleting combination windows, we must make sure that
-     not only p but all its children have been marked as deleted.  */
-  if (! NILP (p->hchild))
-    delete_all_subwindows (XWINDOW (p->hchild));
-  else if (! NILP (p->vchild))
-    delete_all_subwindows (XWINDOW (p->vchild));
-
-  /* Mark this window as deleted.  */
-  p->buffer = p->hchild = p->vchild = Qnil;
-
-  if (! NILP (par->parent))
-    par = XWINDOW (par->parent);
-
-  /* Check if we have a v/hchild with a v/hchild.  In that case remove
-     one of them.  */
-
-  if (! NILP (par->vchild) && ! NILP (XWINDOW (par->vchild)->vchild))
-    {
-      p = XWINDOW (par->vchild);
-      par->vchild = p->vchild;
-      tem = p->vchild;
-    }
-  else if (! NILP (par->hchild) && ! NILP (XWINDOW (par->hchild)->hchild))
-    {
-      p = XWINDOW (par->hchild);
-      par->hchild = p->hchild;
-      tem = p->hchild;
-    }
-  else
-    p = 0;
-
-  if (p)
-    {
-      while (! NILP (tem)) {
-        XWINDOW (tem)->parent = p->parent;
-        if (NILP (XWINDOW (tem)->next))
-          break;
-        tem = XWINDOW (tem)->next;
-      }
-      if (! NILP (tem)) {
-        /* The next of the v/hchild we are removing is now the next of the
-           last child for the v/hchild:
-           Before v/hchild -> v/hchild -> next1 -> next2
-                    |
-                     -> next3
-           After:  v/hchild -> next1 -> next2 -> next3
-        */
-        XWINDOW (tem)->next = p->next;
-        if (! NILP (p->next))
-          XWINDOW (p->next)->prev = tem;
-      }
-      p->next = p->prev = p->vchild = p->hchild = p->buffer = Qnil;
-    }
-
-
-  /* Adjust glyph matrices. */
-  adjust_glyphs (f);
-  UNBLOCK_INPUT;
-}
-
-
-\f
-/***********************************************************************
-                            Window List
- ***********************************************************************/
-
-/* Add window W to *USER_DATA.  USER_DATA is actually a Lisp_Object
-   pointer.  This is a callback function for foreach_window, used in
-   function window_list.  */
-
-static int
-add_window_to_list (w, user_data)
-     struct window *w;
-     void *user_data;
-{
-  Lisp_Object *list = (Lisp_Object *) user_data;
-  Lisp_Object window;
-  XSETWINDOW (window, w);
-  *list = Fcons (window, *list);
-  return 1;
-}
-
-
-/* Return a list of all windows, for use by next_window.  If
-   Vwindow_list is a list, return that list.  Otherwise, build a new
-   list, cache it in Vwindow_list, and return that.  */
+/* Return a list of all windows, for use by next_window.  If
+   Vwindow_list is a list, return that list.  Otherwise, build a new
+   list, cache it in Vwindow_list, and return that.  */
 
 static Lisp_Object
-window_list ()
+window_list (void)
 {
   if (!CONSP (Vwindow_list))
     {
@@ -1822,14 +2007,15 @@ window_list ()
 
    ALL_FRAMES  t means search all frames,
                nil means search just current frame,
-               `visible' means search just visible frames,
-               0 means search visible and iconified frames,
+               `visible' means search just visible frames on the
+                current terminal,
+               0 means search visible and iconified frames on the
+                current terminal,
                a window means search the frame that window belongs to,
                a frame means consider windows on that frame, only.  */
 
 static int
-candidate_window_p (window, owindow, minibuf, all_frames)
-     Lisp_Object window, owindow, minibuf, all_frames;
+candidate_window_p (Lisp_Object window, Lisp_Object owindow, Lisp_Object minibuf, Lisp_Object all_frames)
 {
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
@@ -1890,12 +2076,11 @@ candidate_window_p (window, owindow, minibuf, all_frames)
 
 
 /* Decode arguments as allowed by Fnext_window, Fprevious_window, and
-   Fwindow_list.  See there for the meaning of WINDOW, MINIBUF, and
-   ALL_FRAMES.  */
+   Fwindow_list.  See candidate_window_p for the meaning of WINDOW,
+   MINIBUF, and ALL_FRAMES.  */
 
 static void
-decode_next_window_args (window, minibuf, all_frames)
-     Lisp_Object *window, *minibuf, *all_frames;
+decode_next_window_args (Lisp_Object *window, Lisp_Object *minibuf, Lisp_Object *all_frames)
 {
   if (NILP (*window))
     *window = selected_window;
@@ -1926,12 +2111,6 @@ decode_next_window_args (window, minibuf, all_frames)
     ;
   else if (!EQ (*all_frames, Qt))
     *all_frames = Qnil;
-
-  /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
-     search just current frame, `visible' meaning search just visible
-     frames, 0 meaning search visible and iconified frames, or a
-     window, meaning search the frame that window belongs to, or a
-     frame, meaning consider windows on that frame, only.  */
 }
 
 
@@ -1941,9 +2120,7 @@ decode_next_window_args (window, minibuf, all_frames)
    ALL_FRAMES.  */
 
 static Lisp_Object
-next_window (window, minibuf, all_frames, next_p)
-     Lisp_Object window, minibuf, all_frames;
-     int next_p;
+next_window (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames, int next_p)
 {
   decode_next_window_args (&window, &minibuf, &all_frames);
 
@@ -2007,108 +2184,122 @@ next_window (window, minibuf, all_frames, next_p)
 
 
 DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
-       doc: /* Return window following WINDOW in cyclic ordering of windows.
-WINDOW defaults to the selected window. The optional arguments
-MINIBUF and ALL-FRAMES specify the set of windows to consider.
-
-MINIBUF t means consider the minibuffer window even if the
-minibuffer is not active.  MINIBUF nil or omitted means consider
-the minibuffer window only if the minibuffer is active.  Any
-other value means do not consider the minibuffer window even if
-the minibuffer is active.
-
-Several frames may share a single minibuffer; if the minibuffer
-is active, all windows on all frames that share that minibuffer
-are considered too.  Therefore, if you are using a separate
-minibuffer frame and the minibuffer is active and MINIBUF says it
-counts, `next-window' considers the windows in the frame from
-which you entered the minibuffer, as well as the minibuffer
-window.
+       doc: /* Return live window after WINDOW in the cyclic ordering of windows.
+WINDOW must be a live window and defaults to the selected one.  The
+optional arguments MINIBUF and ALL-FRAMES specify the set of windows to
+consider.
+
+MINIBUF nil or omitted means consider the minibuffer window only if the
+minibuffer is active.  MINIBUF t means consider the minibuffer window
+even if the minibuffer is not active.  Any other value means do not
+consider the minibuffer window even if the minibuffer is active.
+
+ALL-FRAMES nil or omitted means consider all windows on WINDOW's frame,
+plus the minibuffer window if specified by the MINIBUF argument.  If the
+minibuffer counts, consider all windows on all frames that share that
+minibuffer too.  The following non-nil values of ALL-FRAMES have special
+meanings:
+
+- t means consider all windows on all existing frames.
+
+- `visible' means consider all windows on all visible frames.
+
+- 0 (the number zero) means consider all windows on all visible and
+  iconified frames.
+
+- A frame means consider all windows on that frame only.
 
-ALL-FRAMES nil or omitted means consider all windows on WINDOW's
- frame, plus the minibuffer window if specified by the MINIBUF
- argument, see above.  If the minibuffer counts, consider all
- windows on all frames that share that minibuffer too.
-ALL-FRAMES t means consider all windows on all existing frames.
-ALL-FRAMES `visible' means consider all windows on all visible
- frames.
-ALL-FRAMES 0 means consider all windows on all visible and
- iconified frames.
-ALL-FRAMES a frame means consider all windows on that frame only.
 Anything else means consider all windows on WINDOW's frame and no
- others.
+others.
 
 If you use consistent values for MINIBUF and ALL-FRAMES, you can use
 `next-window' to iterate through the entire cycle of acceptable
 windows, eventually ending up back at the window you started with.
 `previous-window' traverses the same cycle, in the reverse order.  */)
-     (window, minibuf, all_frames)
-     Lisp_Object window, minibuf, all_frames;
+  (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
 {
   return next_window (window, minibuf, all_frames, 1);
 }
 
 
 DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
-       doc: /* Return window preceding WINDOW in cyclic ordering of windows.
-WINDOW defaults to the selected window. The optional arguments
-MINIBUF and ALL-FRAMES specify the set of windows to consider.
-For the precise meaning of these arguments see `next-window'.
+       doc: /* Return live window before WINDOW in the cyclic ordering of windows.
+WINDOW must be a live window and defaults to the selected one.  The
+optional arguments MINIBUF and ALL-FRAMES specify the set of windows to
+consider.
+
+MINIBUF nil or omitted means consider the minibuffer window only if the
+minibuffer is active.  MINIBUF t means consider the minibuffer window
+even if the minibuffer is not active.  Any other value means do not
+consider the minibuffer window even if the minibuffer is active.
+
+ALL-FRAMES nil or omitted means consider all windows on WINDOW's frame,
+plus the minibuffer window if specified by the MINIBUF argument.  If the
+minibuffer counts, consider all windows on all frames that share that
+minibuffer too.  The following non-nil values of ALL-FRAMES have special
+meanings:
+
+- t means consider all windows on all existing frames.
+
+- `visible' means consider all windows on all visible frames.
+
+- 0 (the number zero) means consider all windows on all visible and
+  iconified frames.
+
+- A frame means consider all windows on that frame only.
+
+Anything else means consider all windows on WINDOW's frame and no
+others.
 
 If you use consistent values for MINIBUF and ALL-FRAMES, you can
 use `previous-window' to iterate through the entire cycle of
 acceptable windows, eventually ending up back at the window you
 started with.  `next-window' traverses the same cycle, in the
 reverse order.  */)
-     (window, minibuf, all_frames)
-     Lisp_Object window, minibuf, all_frames;
+  (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
 {
   return next_window (window, minibuf, all_frames, 0);
 }
 
 
-DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
-       doc: /* Select another window in cyclic ordering of windows.
-COUNT specifies the number of windows to skip, starting with the
-selected window, before making the selection.  If COUNT is
-positive, skip COUNT windows forwards.  If COUNT is negative,
-skip -COUNT windows backwards.  COUNT zero means do not skip any
-window, so select the selected window.  In an interactive call,
-COUNT is the numeric prefix argument.  Return nil.
+/* Return a list of windows in cyclic ordering.  Arguments are like
+   for `next-window'.  */
 
-This function uses `next-window' for finding the window to select.
-The argument ALL-FRAMES has the same meaning as in `next-window',
-but the MINIBUF argument of `next-window' is always effectively
-nil.  */)
-     (count, all_frames)
-     Lisp_Object count, all_frames;
+static Lisp_Object
+window_list_1 (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
 {
-  Lisp_Object window;
-  int i;
+  Lisp_Object tail, list, rest;
 
-  CHECK_NUMBER (count);
-  window = selected_window;
+  decode_next_window_args (&window, &minibuf, &all_frames);
+  list = Qnil;
 
-  for (i = XINT (count); i > 0; --i)
-    window = Fnext_window (window, Qnil, all_frames);
-  for (; i < 0; ++i)
-    window = Fprevious_window (window, Qnil, all_frames);
+  for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
+    if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
+      list = Fcons (XCAR (tail), list);
 
-  Fselect_window (window, Qnil);
-  return Qnil;
+  /* Rotate the list to start with WINDOW.  */
+  list = Fnreverse (list);
+  rest = Fmemq (window, list);
+  if (!NILP (rest) && !EQ (rest, list))
+    {
+      for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
+       ;
+      XSETCDR (tail, Qnil);
+      list = nconc2 (rest, list);
+    }
+  return list;
 }
 
 
 DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
        doc: /* Return a list of windows on FRAME, starting with WINDOW.
 FRAME nil or omitted means use the selected frame.
-WINDOW nil or omitted means use the selected window.
+WINDOW nil or omitted means use the window selected within FRAME.
 MINIBUF t means include the minibuffer window, even if it isn't active.
 MINIBUF nil or omitted means include the minibuffer window only
 if it's active.
 MINIBUF neither nil nor t means never include the minibuffer window.  */)
-     (frame, minibuf, window)
-     Lisp_Object frame, minibuf, window;
+  (Lisp_Object frame, Lisp_Object minibuf, Lisp_Object window)
 {
   if (NILP (window))
     window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
@@ -2123,36 +2314,41 @@ MINIBUF neither nil nor t means never include the minibuffer window.  */)
 }
 
 
-/* Return a list of windows in cyclic ordering.  Arguments are like
-   for `next-window'.  */
+DEFUN ("window-list-1", Fwindow_list_1, Swindow_list_1, 0, 3, 0,
+       doc: /* Return a list of all live windows.
+WINDOW specifies the first window to list and defaults to the selected
+window.
 
-static Lisp_Object
-window_list_1 (window, minibuf, all_frames)
-     Lisp_Object window, minibuf, all_frames;
-{
-  Lisp_Object tail, list, rest;
+Optional argument MINIBUF nil or omitted means consider the minibuffer
+window only if the minibuffer is active.  MINIBUF t means consider the
+minibuffer window even if the minibuffer is not active.  Any other value
+means do not consider the minibuffer window even if the minibuffer is
+active.
 
-  decode_next_window_args (&window, &minibuf, &all_frames);
-  list = Qnil;
+Optional argument ALL-FRAMES nil or omitted means consider all windows
+on WINDOW's frame, plus the minibuffer window if specified by the
+MINIBUF argument.  If the minibuffer counts, consider all windows on all
+frames that share that minibuffer too.  The following non-nil values of
+ALL-FRAMES have special meanings:
 
-  for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
-    if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
-      list = Fcons (XCAR (tail), list);
+- t means consider all windows on all existing frames.
 
-  /* Rotate the list to start with WINDOW.  */
-  list = Fnreverse (list);
-  rest = Fmemq (window, list);
-  if (!NILP (rest) && !EQ (rest, list))
-    {
-      for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
-       ;
-      XSETCDR (tail, Qnil);
-      list = nconc2 (rest, list);
-    }
-  return list;
-}
+- `visible' means consider all windows on all visible frames.
 
+- 0 (the number zero) means consider all windows on all visible and
+  iconified frames.
 
+- A frame means consider all windows on that frame only.
+
+Anything else means consider all windows on WINDOW's frame and no
+others.
+
+If WINDOW is not on the list of windows returned, some other window will
+be listed first but no error is signaled.  */)
+  (Lisp_Object window, Lisp_Object minibuf, Lisp_Object all_frames)
+{
+  return window_list_1 (window, minibuf, all_frames);
+}
 \f
 /* Look at all windows, performing an operation specified by TYPE
    with argument OBJ.
@@ -2165,23 +2361,17 @@ window_list_1 (window, minibuf, all_frames)
 enum window_loop
 {
   WINDOW_LOOP_UNUSED,
-  GET_BUFFER_WINDOW,           /* Arg is buffer */
-  GET_LRU_WINDOW,              /* Arg is t for full-width windows only */
-  DELETE_OTHER_WINDOWS,                /* Arg is window not to delete */
-  DELETE_BUFFER_WINDOWS,       /* Arg is buffer */
-  GET_LARGEST_WINDOW,
-  UNSHOW_BUFFER,               /* Arg is buffer */
-  REDISPLAY_BUFFER_WINDOWS,    /* Arg is buffer */
+  GET_BUFFER_WINDOW,               /* Arg is buffer */
+  REPLACE_BUFFER_IN_WINDOWS_SAFELY, /* Arg is buffer */
+  REDISPLAY_BUFFER_WINDOWS,        /* Arg is buffer */
   CHECK_ALL_WINDOWS
 };
 
 static Lisp_Object
-window_loop (type, obj, mini, frames)
-     enum window_loop type;
-     Lisp_Object obj, frames;
-     int mini;
+window_loop (enum window_loop type, Lisp_Object obj, int mini, Lisp_Object frames)
 {
   Lisp_Object window, windows, best_window, frame_arg;
+  int frame_best_window_flag = 0;
   struct frame *f;
   struct gcpro gcpro1;
 
@@ -2231,148 +2421,51 @@ window_loop (type, obj, mini, frames)
         is visible, since Fwindow_list skips non-visible frames if
         that is desired, under the control of frame_arg.  */
       if (!MINI_WINDOW_P (w)
-         /* For UNSHOW_BUFFER, we must always consider all windows.  */
-         || type == UNSHOW_BUFFER
+         /* For REPLACE_BUFFER_IN_WINDOWS_SAFELY, we must always
+            consider all windows.  */
+         || type == REPLACE_BUFFER_IN_WINDOWS_SAFELY
          || (mini && minibuf_level > 0))
        switch (type)
          {
          case GET_BUFFER_WINDOW:
            if (EQ (w->buffer, obj)
-               /* Don't find any minibuffer window
-                  except the one that is currently in use.  */
-               && (MINI_WINDOW_P (w)
-                   ? EQ (window, minibuf_window)
-                   : 1))
+               /* Don't find any minibuffer window except the one that
+                  is currently in use.  */
+               && (MINI_WINDOW_P (w) ? EQ (window, minibuf_window) : 1))
              {
-               if (NILP (best_window))
-                 best_window = window;
-               else if (EQ (window, selected_window))
-                 /* Prefer to return selected-window.  */
+               if (EQ (window, selected_window))
+                 /* Preferably return the selected window.  */
                  RETURN_UNGCPRO (window);
-               else if (EQ (Fwindow_frame (window), selected_frame))
-                 /* Prefer windows on the current frame.  */
-                 best_window = window;
-             }
-           break;
-
-         case GET_LRU_WINDOW:
-           /* `obj' is an integer encoding a bitvector.
-              `obj & 1' means consider only full-width windows.
-              `obj & 2' means consider also dedicated windows. */
-           if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
-               || (!(XINT (obj) & 2) && !NILP (w->dedicated))
-               /* Minibuffer windows are always ignored.  */
-               || MINI_WINDOW_P (w))
-             break;
-           if (NILP (best_window)
-               || (XFASTINT (XWINDOW (best_window)->use_time)
-                   > XFASTINT (w->use_time)))
-             best_window = window;
-           break;
-
-         case DELETE_OTHER_WINDOWS:
-           if (!EQ (window, obj))
-             Fdelete_window (window);
-           break;
-
-         case DELETE_BUFFER_WINDOWS:
-           if (EQ (w->buffer, obj))
-             {
-               struct frame *f = XFRAME (WINDOW_FRAME (w));
-
-               /* If this window is dedicated, and in a frame of its own,
-                  kill the frame.  */
-               if (EQ (window, FRAME_ROOT_WINDOW (f))
-                   && !NILP (w->dedicated)
-                   && other_visible_frames (f))
-                 {
-                   /* Skip the other windows on this frame.
-                      There might be one, the minibuffer!  */
-                   while (CONSP (XCDR (windows))
-                          && EQ (XWINDOW (XCAR (windows))->frame,
-                                 XWINDOW (XCAR (XCDR (windows)))->frame))
-                     windows = XCDR (windows);
-
-                   /* Now we can safely delete the frame.  */
-                   delete_frame (w->frame, Qnil);
-                 }
-               else if (NILP (w->parent))
+               else if (EQ (XWINDOW (window)->frame, selected_frame)
+                        && !frame_best_window_flag)
+                 /* Prefer windows on the current frame (but don't
+                    choose another one if we have one already).  */
                  {
-                   /* If we're deleting the buffer displayed in the
-                      only window on the frame, find a new buffer to
-                      display there.  */
-                   Lisp_Object buffer;
-                   buffer = Fother_buffer (obj, Qnil, w->frame);
-                   /* Reset dedicated state of window.  */
-                   w->dedicated = Qnil;
-                   Fset_window_buffer (window, buffer, Qnil);
-                   if (EQ (window, selected_window))
-                     Fset_buffer (w->buffer);
+                   best_window = window;
+                   frame_best_window_flag = 1;
                  }
-               else
-                 Fdelete_window (window);
+               else if (NILP (best_window))
+                 best_window = window;
              }
            break;
 
-         case GET_LARGEST_WINDOW:
-           { /* nil `obj' means to ignore dedicated windows.  */
-             /* Ignore dedicated windows and minibuffers.  */
-             if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
-               break;
-
-             if (NILP (best_window))
-               best_window = window;
-             else
-               {
-                 struct window *b = XWINDOW (best_window);
-                 if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
-                     > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
-                   best_window = window;
-               }
-           }
-           break;
-
-         case UNSHOW_BUFFER:
+         case REPLACE_BUFFER_IN_WINDOWS_SAFELY:
+           /* We could simply check whether the buffer shown by window
+              is live, and show another buffer in case it isn't.  */
            if (EQ (w->buffer, obj))
              {
-               Lisp_Object buffer;
-               struct frame *f = XFRAME (w->frame);
-
-               /* Find another buffer to show in this window.  */
-               buffer = Fother_buffer (obj, Qnil, w->frame);
-
-               /* If this window is dedicated, and in a frame of its own,
-                  kill the frame.  */
-               if (EQ (window, FRAME_ROOT_WINDOW (f))
-                   && !NILP (w->dedicated)
-                   && other_visible_frames (f))
-                 {
-                   /* Skip the other windows on this frame.
-                      There might be one, the minibuffer!  */
-                   while (CONSP (XCDR (windows))
-                          && EQ (XWINDOW (XCAR (windows))->frame,
-                                 XWINDOW (XCAR (XCDR (windows)))->frame))
-                     windows = XCDR (windows);
-
-                   /* Now we can safely delete the frame.  */
-                   delete_frame (w->frame, Qnil);
-                 }
-               else if (!NILP (w->dedicated) && !NILP (w->parent))
-                 {
-                   Lisp_Object window;
-                   XSETWINDOW (window, w);
-                   /* If this window is dedicated and not the only window
-                      in its frame, then kill it.  */
-                   Fdelete_window (window);
-                 }
-               else
-                 {
-                   /* Otherwise show a different buffer in the window.  */
-                   w->dedicated = Qnil;
-                   Fset_window_buffer (window, buffer, Qnil);
-                   if (EQ (window, selected_window))
-                     Fset_buffer (w->buffer);
-                 }
+               /* Undedicate WINDOW.  */
+               w->dedicated = Qnil;
+               /* Make WINDOW show the buffer returned by
+                  other_buffer_safely, don't run any hooks.  */
+               set_window_buffer
+                 (window, other_buffer_safely (w->buffer), 0, 0);
+               /* If WINDOW is the selected window, make its buffer
+                  current.  But do so only if the window shows the
+                  current buffer (Bug#6454).  */
+               if (EQ (window, selected_window)
+                   && XBUFFER (w->buffer) == current_buffer)
+                 Fset_buffer (w->buffer);
              }
            break;
 
@@ -2380,7 +2473,7 @@ window_loop (type, obj, mini, frames)
            if (EQ (w->buffer, obj))
              {
                mark_window_display_accurate (window, 0);
-               w->update_mode_line = Qt;
+               w->update_mode_line = 1;
                XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
                ++update_mode_lines;
                best_window = window;
@@ -2390,7 +2483,7 @@ window_loop (type, obj, mini, frames)
            /* Check for a window that has a killed buffer.  */
          case CHECK_ALL_WINDOWS:
            if (! NILP (w->buffer)
-               && NILP (XBUFFER (w->buffer)->name))
+               && NILP (BVAR (XBUFFER (w->buffer), name)))
              abort ();
            break;
 
@@ -2405,972 +2498,391 @@ window_loop (type, obj, mini, frames)
 
 /* Used for debugging.  Abort if any window has a dead buffer.  */
 
+extern void check_all_windows (void) EXTERNALLY_VISIBLE;
 void
-check_all_windows ()
+check_all_windows (void)
 {
   window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
 }
 
-DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
-       doc: /* Return the window least recently selected or used for display.
-\(LRU means Least Recently Used.)
-
-Return a full-width window if possible.
-A minibuffer window is never a candidate.
-A dedicated window is never a candidate, unless DEDICATED is non-nil,
-  so if all windows are dedicated, the value is nil.
-If optional argument FRAME is `visible', search all visible frames.
-If FRAME is 0, search all visible and iconified frames.
-If FRAME is t, search all frames.
-If FRAME is nil, search only the selected frame.
-If FRAME is a frame, search only that frame.  */)
-  (frame, dedicated)
-     Lisp_Object frame, dedicated;
-{
-  register Lisp_Object w;
-  /* First try for a window that is full-width */
-  w = window_loop (GET_LRU_WINDOW,
-                  NILP (dedicated) ? make_number (1) : make_number (3),
-                  0, frame);
-  if (!NILP (w) && !EQ (w, selected_window))
-    return w;
-  /* If none of them, try the rest */
-  return window_loop (GET_LRU_WINDOW,
-                     NILP (dedicated) ? make_number (0) : make_number (2),
-                     0, frame);
-}
-
-DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
-       doc: /* Return the largest window in area.
-A minibuffer window is never a candidate.
-A dedicated window is never a candidate unless DEDICATED is non-nil,
-  so if all windows are dedicated, the value is nil.
-If optional argument FRAME is `visible', search all visible frames.
-If FRAME is 0, search all visible and iconified frames.
-If FRAME is t, search all frames.
-If FRAME is nil, search only the selected frame.
-If FRAME is a frame, search only that frame.  */)
-    (frame, dedicated)
-     Lisp_Object frame, dedicated;
-{
-  return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
-                     frame);
-}
-
 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 0, 2, 0,
        doc: /* Return a window currently displaying BUFFER-OR-NAME, or nil if none.
-BUFFER-OR-NAME may be a buffer or a buffer name and defaults to the
-current buffer.
-If optional argument FRAME is `visible', search all visible frames.
-If optional argument FRAME is 0, search all visible and iconified frames.
-If FRAME is t, search all frames.
-If FRAME is nil, search only the selected frame.
-If FRAME is a frame, search only that frame.  */)
-     (buffer_or_name, frame)
-     Lisp_Object buffer_or_name, frame;
-{
-  Lisp_Object buffer;
-
-  if (NILP (buffer_or_name))
-    buffer = Fcurrent_buffer ();
-  else
-    buffer = Fget_buffer (buffer_or_name);
-
-  if (BUFFERP (buffer))
-    return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
-  else
-    return Qnil;
-}
-
-DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
-       0, 1, "",
-       doc: /* Make WINDOW (or the selected window) fill its frame.
-Only the frame WINDOW is on is affected.
-This function tries to reduce display jumps by keeping the text
-previously visible in WINDOW in the same place on the frame.  Doing this
-depends on the value of (window-start WINDOW), so if calling this
-function in a program gives strange scrolling, make sure the
-window-start value is reasonable when this function is called.  */)
-     (window)
-     Lisp_Object window;
-{
-  struct window *w;
-  int startpos;
-  int top, new_top;
-
-  if (NILP (window))
-    window = selected_window;
-  else
-    CHECK_LIVE_WINDOW (window);
-  w = XWINDOW (window);
-
-  startpos = marker_position (w->start);
-  top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+BUFFER-OR-NAME may be a buffer or a buffer name and defaults to
+the current buffer.
 
-  if (MINI_WINDOW_P (w) && top > 0)
-    error ("Can't expand minibuffer to full frame");
+The optional argument ALL-FRAMES specifies the frames to consider:
 
-  window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
-
-  /* Try to minimize scrolling, by setting the window start to the point
-     will cause the text at the old window start to be at the same place
-     on the frame.  But don't try to do this if the window start is
-     outside the visible portion (as might happen when the display is
-     not current, due to typeahead).  */
-  new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
-  if (new_top != top
-      && startpos >= BUF_BEGV (XBUFFER (w->buffer))
-      && startpos <= BUF_ZV (XBUFFER (w->buffer)))
-    {
-      struct position pos;
-      struct buffer *obuf = current_buffer;
+- t means consider all windows on all existing frames.
 
-      Fset_buffer (w->buffer);
-      /* This computation used to temporarily move point, but that can
-        have unwanted side effects due to text properties.  */
-      pos = *vmotion (startpos, -top, w);
+- `visible' means consider all windows on all visible frames.
 
-      set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
-      w->window_end_valid = Qnil;
-      w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
-                              || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
-                             : Qnil);
-      /* We need to do this, so that the window-scroll-functions
-        get called.  */
-      w->optional_new_start = Qt;
+- 0 (the number zero) means consider all windows on all visible
+    and iconified frames.
 
-      set_buffer_internal (obuf);
-    }
+- A frame means consider all windows on that frame only.
 
-  return Qnil;
-}
-
-DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
-       0, 2, "bDelete windows on (buffer): ",
-       doc: /* Delete all windows showing BUFFER-OR-NAME.
-BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
-defaults to the current buffer.
-
-Optional second argument FRAME controls which frames are affected.
-If optional argument FRAME is `visible', search all visible frames.
-If FRAME is 0, search all visible and iconified frames.
-If FRAME is nil, search all frames.
-If FRAME is t, search only the selected frame.
-If FRAME is a frame, search only that frame.
-When a window showing BUFFER-OR-NAME is dedicated and the only window of
-its frame, that frame is deleted when there are other frames left.  */)
-     (buffer_or_name, frame)
-     Lisp_Object buffer_or_name, frame;
+Any other value of ALL-FRAMES means consider all windows on the
+selected frame and no others.  */)
+     (Lisp_Object buffer_or_name, Lisp_Object all_frames)
 {
   Lisp_Object buffer;
 
-  /* FRAME uses t and nil to mean the opposite of what window_loop
-     expects.  */
-  if (NILP (frame))
-    frame = Qt;
-  else if (EQ (frame, Qt))
-    frame = Qnil;
-
   if (NILP (buffer_or_name))
     buffer = Fcurrent_buffer ();
   else
-    {
-      buffer = Fget_buffer (buffer_or_name);
-      CHECK_BUFFER (buffer);
-    }
-
-  window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
-
-  return Qnil;
-}
-
-DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
-       Sreplace_buffer_in_windows,
-       0, 1, "bReplace buffer in windows: ",
-       doc: /* Replace BUFFER-OR-NAME with some other buffer in all windows showing it.
-BUFFER-OR-NAME may be a buffer or the name of an existing buffer and
-defaults to the current buffer.
-
-When a window showing BUFFER-OR-NAME is dedicated that window is
-deleted.  If that window is the only window on its frame, that frame is
-deleted too when there are other frames left.  If there are no other
-frames left, some other buffer is displayed in that window.  */)
-     (buffer_or_name)
-     Lisp_Object buffer_or_name;
-{
-  Lisp_Object buffer;
+    buffer = Fget_buffer (buffer_or_name);
 
-  if (NILP (buffer_or_name))
-    buffer = Fcurrent_buffer ();
+  if (BUFFERP (buffer))
+    return window_loop (GET_BUFFER_WINDOW, buffer, 1, all_frames);
   else
-    {
-      buffer = Fget_buffer (buffer_or_name);
-      CHECK_BUFFER (buffer);
-    }
-
-  window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
-
-  return Qnil;
+    return Qnil;
 }
 
-/* Replace BUFFER with some other buffer in all windows
-   of all frames, even those on other keyboards.  */
-
-void
-replace_buffer_in_all_windows (buffer)
-     Lisp_Object buffer;
+static Lisp_Object
+resize_root_window (Lisp_Object window, Lisp_Object delta, Lisp_Object horizontal, Lisp_Object ignore)
 {
-  Lisp_Object tail, frame;
-
-  /* A single call to window_loop won't do the job
-     because it only considers frames on the current keyboard.
-     So loop manually over frames, and handle each one.  */
-  FOR_EACH_FRAME (tail, frame)
-    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
+  return call4 (Qwindow_resize_root_window, window, delta, horizontal, ignore);
 }
-\f
-/* Set the height of WINDOW and all its inferiors.  */
 
-/* The smallest acceptable dimensions for a window.  Anything smaller
-   might crash Emacs.  */
 
-#define MIN_SAFE_WINDOW_WIDTH  (2)
-#define MIN_SAFE_WINDOW_HEIGHT (1)
+DEFUN ("delete-other-windows-internal", Fdelete_other_windows_internal,
+       Sdelete_other_windows_internal, 0, 2, "",
+       doc: /* Make WINDOW fill its frame.
+Only the frame WINDOW is on is affected.  WINDOW may be any window and
+defaults to the selected one.
 
-/* For wp non-zero the total number of columns of window w.  Otherwise
-   the total number of lines of w.  */
+Optional argument ROOT, if non-nil, must specify an internal window such
+that WINDOW is in its window subtree.  If this is the case, replace ROOT
+by WINDOW and leave alone any windows not part of ROOT's subtree.
 
-#define WINDOW_TOTAL_SIZE(w, wp) \
-  (wp ? WINDOW_TOTAL_COLS (w) : WINDOW_TOTAL_LINES (w))
-
-/* If *ROWS or *COLS are too small a size for FRAME, set them to the
-   minimum allowable size.  */
-
-void
-check_frame_size (frame, rows, cols)
-     FRAME_PTR frame;
-     int *rows, *cols;
+When WINDOW is live try to reduce display jumps by keeping the text
+previously visible in WINDOW in the same place on the frame.  Doing this
+depends on the value of (window-start WINDOW), so if calling this
+function in a program gives strange scrolling, make sure the
+window-start value is reasonable when this function is called.  */)
+     (Lisp_Object window, Lisp_Object root)
 {
-  /* For height, we have to see:
-     how many windows the frame has at minimum (one or two),
-     and whether it has a menu bar or other special stuff at the top.  */
-  int min_height
-    = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
-       ? MIN_SAFE_WINDOW_HEIGHT
-       : 2 * MIN_SAFE_WINDOW_HEIGHT);
-
-  if (FRAME_TOP_MARGIN (frame) > 0)
-    min_height += FRAME_TOP_MARGIN (frame);
-
-  if (*rows < min_height)
-    *rows = min_height;
-  if (*cols  < MIN_SAFE_WINDOW_WIDTH)
-    *cols = MIN_SAFE_WINDOW_WIDTH;
-}
-
-/* Value is non-zero if window W is fixed-size.  WIDTH_P non-zero means
-   check if W's width can be changed, otherwise check W's height.
-   CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
-   siblings, too.  If none of the siblings is resizable, WINDOW isn't
-   either.  */
+  struct window *w, *r, *s;
+  struct frame *f;
+  Lisp_Object sibling, pwindow, swindow IF_LINT (= Qnil), delta;
+  ptrdiff_t startpos IF_LINT (= 0);
+  int top IF_LINT (= 0), new_top, resize_failed;
 
-static int
-window_fixed_size_p (w, width_p, check_siblings_p)
-     struct window *w;
-     int width_p, check_siblings_p;
-{
-  int fixed_p;
-  struct window *c;
+  w = decode_any_window (window);
+  XSETWINDOW (window, w);
+  f = XFRAME (w->frame);
 
-  if (!NILP (w->hchild))
+  if (NILP (root))
+    /* ROOT is the frame's root window.  */
     {
-      c = XWINDOW (w->hchild);
-
-      if (width_p)
-       {
-         /* A horizontal combination is fixed-width if all of if its
-            children are.  */
-         while (c && window_fixed_size_p (c, width_p, 0))
-           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-         fixed_p = c == NULL;
-       }
-      else
-       {
-         /* A horizontal combination is fixed-height if one of if its
-            children is.  */
-         while (c && !window_fixed_size_p (c, width_p, 0))
-           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-         fixed_p = c != NULL;
-       }
+      root = FRAME_ROOT_WINDOW (f);
+      r = XWINDOW (root);
     }
-  else if (!NILP (w->vchild))
+  else
+    /* ROOT must be an ancestor of WINDOW.  */
     {
-      c = XWINDOW (w->vchild);
+      r = decode_any_window (root);
+      pwindow = XWINDOW (window)->parent;
+      while (!NILP (pwindow))
+       if (EQ (pwindow, root))
+         break;
+       else
+         pwindow = XWINDOW (pwindow)->parent;
+      if (!EQ (pwindow, root))
+       error ("Specified root is not an ancestor of specified window");
+    }
 
-      if (width_p)
-       {
-         /* A vertical combination is fixed-width if one of if its
-            children is.  */
-         while (c && !window_fixed_size_p (c, width_p, 0))
-           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-         fixed_p = c != NULL;
-       }
-      else
+  if (EQ (window, root))
+    /* A noop.  */
+    return Qnil;
+  /* I don't understand the "top > 0" part below.  If we deal with a
+     standalone minibuffer it would have been caught by the preceding
+     test.  */
+  else if (MINI_WINDOW_P (w)) /* && top > 0) */
+    error ("Can't expand minibuffer to full frame");
+
+  if (!NILP (w->buffer))
+    {
+      startpos = marker_position (w->start);
+      top = WINDOW_TOP_EDGE_LINE (w)
+       - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+      /* Make sure WINDOW is the frame's selected window.  */
+      if (!EQ (window, FRAME_SELECTED_WINDOW (f)))
        {
-         /* A vertical combination is fixed-height if all of if its
-            children are.  */
-         while (c && window_fixed_size_p (c, width_p, 0))
-           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-         fixed_p = c == NULL;
+         if (EQ (selected_frame, w->frame))
+           Fselect_window (window, Qnil);
+         else
+           FRAME_SELECTED_WINDOW (f) = window;
        }
     }
-  else if (BUFFERP (w->buffer))
+  else
     {
-      struct buffer *old = current_buffer;
-      Lisp_Object val;
-
-      current_buffer = XBUFFER (w->buffer);
-      val = find_symbol_value (Qwindow_size_fixed);
-      current_buffer = old;
-
-      fixed_p = 0;
-      if (!EQ (val, Qunbound))
+      /* See if the frame's selected window is a part of the window
+        subtree rooted at WINDOW, by finding all the selected window's
+        parents and comparing each one with WINDOW.  If it isn't we
+        need a new selected window for this frame.  */
+      swindow = FRAME_SELECTED_WINDOW (f);
+      while (1)
        {
-         fixed_p = !NILP (val);
+         pwindow = swindow;
+         while (!NILP (pwindow) && !EQ (window, pwindow))
+           pwindow = XWINDOW (pwindow)->parent;
 
-         if (fixed_p
-             && ((EQ (val, Qheight) && width_p)
-                 || (EQ (val, Qwidth) && !width_p)))
-           fixed_p = 0;
+         if (EQ (window, pwindow))
+           /* If WINDOW is an ancestor of SWINDOW, then SWINDOW is ok
+              as the new selected window.  */
+           break;
+         else
+           /* Else try the previous window of SWINDOW.  */
+           swindow = Fprevious_window (swindow, Qlambda, Qnil);
        }
 
-      /* Can't tell if this one is resizable without looking at
-        siblings.  If all siblings are fixed-size this one is too.  */
-      if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
+      if (!EQ (swindow, FRAME_SELECTED_WINDOW (f)))
        {
-         Lisp_Object child;
-
-         for (child = w->prev; WINDOWP (child); child = XWINDOW (child)->prev)
-           if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
-             break;
-
-         if (NILP (child))
-           for (child = w->next; WINDOWP (child); child = XWINDOW (child)->next)
-             if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
-               break;
-
-         if (NILP (child))
-           fixed_p = 1;
+         if (EQ (selected_frame, w->frame))
+           Fselect_window (swindow, Qnil);
+         else
+           FRAME_SELECTED_WINDOW (f) = swindow;
        }
     }
-  else
-    fixed_p = 1;
-
-  return fixed_p;
-}
-
-/* Return minimum size of leaf window W.  WIDTH_P non-zero means return
-   the minimum width of W, WIDTH_P zero means return the minimum height
-   of W.  SAFE_P non-zero means ignore window-min-height|width but just
-   return values that won't crash Emacs and don't hide components like
-   fringes, scrollbars, or modelines.  If WIDTH_P is zero and W is the
-   minibuffer window, always return 1.  */
-
-static int
-window_min_size_2 (w, width_p, safe_p)
-     struct window *w;
-     int width_p, safe_p;
-{
-  /* We should consider buffer-local values of window_min_height and
-     window_min_width here.  */
-  if (width_p)
-    {
-      int safe_size = (MIN_SAFE_WINDOW_WIDTH
-                      + WINDOW_FRINGE_COLS (w)
-                      + WINDOW_SCROLL_BAR_COLS (w));
-
-      return safe_p ? safe_size : max (window_min_width, safe_size);
-    }
-  else if (MINI_WINDOW_P (w))
-    return 1;
-  else
-    {
-      int safe_size = (MIN_SAFE_WINDOW_HEIGHT
-                      + ((BUFFERP (w->buffer)
-                          && !NILP (XBUFFER (w->buffer)->mode_line_format))
-                         ? 1 : 0));
 
-      return safe_p ? safe_size : max (window_min_height, safe_size);
+  BLOCK_INPUT;
+  if (!FRAME_INITIAL_P (f))
+    {
+        Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+
+      /* We are going to free the glyph matrices of WINDOW, and with
+        that we might lose any information about glyph rows that have
+        some of their glyphs highlighted in mouse face.  (These rows
+        are marked with a non-zero mouse_face_p flag.)  If WINDOW
+        indeed has some glyphs highlighted in mouse face, signal to
+        frame's up-to-date hook that mouse highlight was overwritten,
+        so that it will arrange for redisplaying the highlight.  */
+      if (EQ (hlinfo->mouse_face_window, window))
+       {
+         hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
+         hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
+         hlinfo->mouse_face_window = Qnil;
+       }
     }
-}
-
-/* Return minimum size of window W, not taking fixed-width windows into
-   account.  WIDTH_P non-zero means return the minimum width, otherwise
-   return the minimum height.  SAFE_P non-zero means ignore
-   window-min-height|width but just return values that won't crash Emacs
-   and don't hide components like fringes, scrollbars, or modelines.  If
-   W is a combination window, compute the minimum size from the minimum
-   sizes of W's children.  */
+  free_window_matrices (r);
 
-static int
-window_min_size_1 (w, width_p, safe_p)
-     struct window *w;
-     int width_p, safe_p;
-{
-  struct window *c;
-  int size;
+  windows_or_buffers_changed++;
+  Vwindow_list = Qnil;
+  FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+  resize_failed = 0;
 
-  if (!NILP (w->hchild))
+  if (NILP (w->buffer))
     {
-      /* W is a horizontal combination.  */
-      c = XWINDOW (w->hchild);
-      size = 0;
-
-      if (width_p)
-       {
-         /* The minimum width of a horizontal combination is the sum of
-            the minimum widths of its children.  */
-         while (c)
-           {
-             size += window_min_size_1 (c, 1, safe_p);
-             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-           }
-       }
+      /* Resize child windows vertically.  */
+      XSETINT (delta, XINT (r->total_lines) - XINT (w->total_lines));
+      w->top_line = r->top_line;
+      resize_root_window (window, delta, Qnil, Qnil);
+      if (window_resize_check (w, 0))
+       window_resize_apply (w, 0);
       else
        {
-         /* The minimum height of a horizontal combination is the
-            maximum of the minimum heights of its children.  */
-         while (c)
-           {
-             size = max (window_min_size_1 (c, 0, safe_p), size);
-             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-           }
+         resize_root_window (window, delta, Qnil, Qt);
+         if (window_resize_check (w, 0))
+           window_resize_apply (w, 0);
+         else
+           resize_failed = 1;
        }
-    }
-  else if (!NILP (w->vchild))
-    {
-      /* W is a vertical combination.  */
-      c = XWINDOW (w->vchild);
-      size = 0;
 
-      if (width_p)
+      /* Resize child windows horizontally.  */
+      if (!resize_failed)
        {
-         /* The minimum width of a vertical combination is the maximum
-            of the minimum widths of its children.  */
-         while (c)
+         w->left_col = r->left_col;
+         XSETINT (delta, XINT (r->total_cols) - XINT (w->total_cols));
+         w->left_col = r->left_col;
+         resize_root_window (window, delta, Qt, Qnil);
+         if (window_resize_check (w, 1))
+           window_resize_apply (w, 1);
+         else
            {
-             size = max (window_min_size_1 (c, 1, safe_p), size);
-             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+             resize_root_window (window, delta, Qt, Qt);
+             if (window_resize_check (w, 1))
+               window_resize_apply (w, 1);
+             else
+               resize_failed = 1;
            }
        }
-      else
+
+      if (resize_failed)
+       /* Play safe, if we still can ...  */
        {
-         /* The minimum height of a vertical combination is the sum of
-            the minimum height of its children.  */
-         while (c)
-           {
-             size += window_min_size_1 (c, 0, safe_p);
-             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
-           }
+         window = swindow;
+         w = XWINDOW (window);
        }
     }
-  else
-    /* W is a leaf window.  */
-    size = window_min_size_2 (w, width_p, safe_p);
-
-  return size;
-}
-
-/* Return the minimum size of window W, taking fixed-size windows into
-   account.  WIDTH_P non-zero means return the minimum width, otherwise
-   return the minimum height.  SAFE_P non-zero means ignore
-   window-min-height|width but just return values that won't crash Emacs
-   and don't hide components like fringes, scrollbars, or modelines.
-   IGNORE_FIXED_P non-zero means ignore if W is fixed-size.  Set *FIXED
-   to 1 if W is fixed-size unless FIXED is null.  */
-
-static int
-window_min_size (w, width_p, safe_p, ignore_fixed_p, fixed)
-     struct window *w;
-     int width_p, safe_p, ignore_fixed_p, *fixed;
-{
-  int size, fixed_p;
-
-  if (ignore_fixed_p)
-    fixed_p = 0;
-  else
-    fixed_p = window_fixed_size_p (w, width_p, 1);
-
-  if (fixed)
-    *fixed = fixed_p;
-
-  if (fixed_p)
-    size = WINDOW_TOTAL_SIZE (w, width_p);
-  else
-    size = window_min_size_1 (w, width_p, safe_p);
-
-  return size;
-}
-
-
-/* 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 (w)
-     struct window *w;
-{
-  int box_cols = (WINDOW_TOTAL_COLS (w)
-                 - WINDOW_FRINGE_COLS (w)
-                 - WINDOW_SCROLL_BAR_COLS (w));
-  int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
-                    + WINDOW_RIGHT_MARGIN_COLS (w));
-
-  if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
-    return 1;
-
-  if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
-    return 0;
 
-  /* Window's text area is too narrow, but reducing the window
-     margins will fix that.  */
-  margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
-  if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
+  /* Cleanly unlink WINDOW from window-tree.  */
+  if (!NILP (w->prev))
+    /* Get SIBLING above (on the left of) WINDOW.  */
     {
-      if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
-       w->left_margin_cols = w->right_margin_cols
-         = make_number (margin_cols/2);
-      else
-       w->right_margin_cols = make_number (margin_cols);
+      sibling = w->prev;
+      s = XWINDOW (sibling);
+      s->next = w->next;
+      if (!NILP (s->next))
+       XWINDOW (s->next)->prev = sibling;
     }
   else
-    w->left_margin_cols = make_number (margin_cols);
-  return 1;
-}
-
-/* Calculate new sizes for windows in the list FORWARD when their
-   compound size goes from TOTAL to SIZE.  TOTAL must be greater than
-   SIZE.  The number of windows in FORWARD is NCHILDREN, and the number
-   that can shrink is SHRINKABLE.  Fixed-size windows may be shrunk if
-   and only if RESIZE_FIXED_P is non-zero.  WIDTH_P non-zero means
-   shrink columns, otherwise shrink lines.
-
-   SAFE_P zero means windows may be sized down to window-min-height
-   lines (window-min-window columns for WIDTH_P non-zero).  SAFE_P
-   non-zero means windows may be sized down to their minimum safe sizes
-   taking into account the space needed to display modelines, fringes,
-   and scrollbars.
-
-   This function returns an allocated array of new sizes that the caller
-   must free.  A size -1 means the window is fixed and RESIZE_FIXED_P is
-   zero.  A size zero means the window shall be deleted.  Array index 0
-   refers to the first window in FORWARD, 1 to the second, and so on.
-
-   This function resizes windows proportionally to their size.  It also
-   tries to preserve smaller windows by resizing larger windows before
-   resizing any window to zero.  If resize_proportionally is non-nil for
-   a specific window, it will attempt to strictly resize that window
-   proportionally, even at the expense of deleting smaller windows.  */
-static int *
-shrink_windows (total, size, nchildren, shrinkable, resize_fixed_p,
-               forward, width_p, safe_p)
-     int total, size, nchildren, shrinkable;
-     int resize_fixed_p, width_p, safe_p;
-     Lisp_Object forward;
-{
-  int available_resize = 0;
-  int *new_sizes, *min_sizes;
-  struct window *c;
-  Lisp_Object child;
-  int smallest = total;
-  int total_removed = 0;
-  int total_shrink = total - size;
-  int i;
-
-  new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
-  min_sizes = xmalloc (sizeof (*min_sizes) * nchildren);
-
-  for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
+    /* Get SIBLING below (on the right of) WINDOW.  */
     {
-      int child_size;
-
-      c = XWINDOW (child);
-      child_size = WINDOW_TOTAL_SIZE (c, width_p);
-
-      if (!resize_fixed_p && window_fixed_size_p (c, width_p, 0))
-        new_sizes[i] = -1;
+      sibling = w->next;
+      s = XWINDOW (sibling);
+      s->prev = Qnil;
+      if (!NILP (XWINDOW (w->parent)->vchild))
+       XWINDOW (w->parent)->vchild = sibling;
       else
-        {
-          new_sizes[i] = child_size;
-          min_sizes[i] = window_min_size_1 (c, width_p, safe_p);
-          if (child_size > min_sizes[i]
-             && NILP (c->resize_proportionally))
-            available_resize += child_size - min_sizes[i];
-        }
-    }
-  /* We might need to shrink some windows to zero.  Find the smallest
-     windows and set them to 0 until we can fulfil the new size.  */
-
-  while (shrinkable > 1 && size + available_resize < total)
-    {
-      for (i = 0; i < nchildren; ++i)
-        if (new_sizes[i] > 0 && smallest > new_sizes[i])
-          smallest = new_sizes[i];
-
-      for (i = 0; i < nchildren; ++i)
-        if (new_sizes[i] == smallest)
-          {
-            /* Resize this window down to zero.  */
-            new_sizes[i] = 0;
-            if (smallest > min_sizes[i])
-              available_resize -= smallest - min_sizes[i];
-            available_resize += smallest;
-            --shrinkable;
-            total_removed += smallest;
-
-            /* We don't know what the smallest is now.  */
-            smallest = total;
-
-            /* Out of for, just remove one window at the time and
-               check again if we have enough space.  */
-            break;
-          }
-    }
-
-  /* Now, calculate the new sizes.  Try to shrink each window
-     proportional to its size.  */
-  for (i = 0; i < nchildren; ++i)
-    {
-      if (new_sizes[i] > min_sizes[i])
-        {
-          int to_shrink = total_shrink * new_sizes[i] / total;
-
-          if (new_sizes[i] - to_shrink < min_sizes[i])
-            to_shrink = new_sizes[i] - min_sizes[i];
-          new_sizes[i] -= to_shrink;
-          total_removed += to_shrink;
-        }
+       XWINDOW (w->parent)->hchild = sibling;
     }
 
-  /* Any reminder due to rounding, we just subtract from windows
-     that are left and still can be shrunk.  */
-  while (total_shrink > total_removed)
-    {
-      int nonzero_sizes = 0;
-      int nonzero_idx = -1;
-
-      for (i = 0; i < nchildren; ++i)
-        if (new_sizes[i] > 0)
-          {
-            ++nonzero_sizes;
-            nonzero_idx = i;
-          }
-
-      for (i = 0; i < nchildren; ++i)
-        if (new_sizes[i] > min_sizes[i])
-          {
-            --new_sizes[i];
-            ++total_removed;
-
-            /* Out of for, just shrink one window at the time and
-               check again if we have enough space.  */
-            break;
-          }
-
-      /* Special case, only one window left.  */
-      if (nonzero_sizes == 1)
-        break;
-    }
-
-  /* Any surplus due to rounding, we add to windows that are left.  */
-  while (total_shrink < total_removed)
+  /* Delete ROOT and all child windows of ROOT.  */
+  if (!NILP (r->vchild))
     {
-      for (i = 0; i < nchildren; ++i)
-        {
-          if (new_sizes[i] != 0 && total_shrink < total_removed)
-            {
-              ++new_sizes[i];
-              --total_removed;
-              break;
-            }
-        }
+      delete_all_child_windows (r->vchild);
+      r->vchild = Qnil;
     }
-
-  xfree (min_sizes);
-
-  return new_sizes;
-}
-
-/* Set WINDOW's height or width to SIZE.  WIDTH_P non-zero means set
-   WINDOW's width.  Resize WINDOW's children, if any, so that they keep
-   their proportionate size relative to WINDOW.
-
-   If FIRST_ONLY is 1, change only the first of WINDOW's children when
-   they are in series.  If LAST_ONLY is 1, change only the last of
-   WINDOW's children when they are in series.
-
-   Propagate WINDOW's top or left edge position to children.  Delete
-   windows that become too small unless NODELETE_P is 1.  When
-   NODELETE_P equals 2 do not honor settings for window-min-height and
-   window-min-width when resizing windows but use safe defaults instead.
-   This should give better behavior when resizing frames.  */
-
-static void
-size_window (window, size, width_p, nodelete_p, first_only, last_only)
-     Lisp_Object window;
-     int size, width_p, nodelete_p;
-     int first_only, last_only;
-{
-  struct window *w = XWINDOW (window);
-  struct window *c;
-  Lisp_Object child, *forward, *sideward;
-  int old_size = WINDOW_TOTAL_SIZE (w, width_p);
-
-  size = max (0, size);
-
-  /* Delete WINDOW if it's too small.  */
-  if (nodelete_p != 1 && !NILP (w->parent)
-      && size < window_min_size_1 (w, width_p, nodelete_p == 2))
+  else if (!NILP (r->hchild))
     {
-      delete_window (window);
-      return;
+      delete_all_child_windows (r->hchild);
+      r->hchild = Qnil;
     }
 
-  /* Set redisplay hints.  */
-  w->last_modified = make_number (0);
-  w->last_overlay_modified = make_number (0);
-  windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
+  replace_window (root, window, 1);
 
-  if (width_p)
-    {
-      sideward = &w->vchild;
-      forward = &w->hchild;
-      w->total_cols = make_number (size);
-      adjust_window_margins (w);
-    }
-  else
+  /* This must become SWINDOW anyway ....... */
+  if (!NILP (w->buffer) && !resize_failed)
     {
-      sideward = &w->hchild;
-      forward = &w->vchild;
-      w->total_lines = make_number (size);
-      w->orig_total_lines = Qnil;
-    }
-
-  if (!NILP (*sideward))
-    {
-      /* We have a chain of parallel siblings whose size should all change.  */
-      for (child = *sideward; !NILP (child); child = c->next)
+      /* Try to minimize scrolling, by setting the window start to the
+        point will cause the text at the old window start to be at the
+        same place on the frame.  But don't try to do this if the
+        window start is outside the visible portion (as might happen
+        when the display is not current, due to typeahead).  */
+      new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
+      if (new_top != top
+         && startpos >= BUF_BEGV (XBUFFER (w->buffer))
+         && startpos <= BUF_ZV (XBUFFER (w->buffer)))
        {
-         c = XWINDOW (child);
-         if (width_p)
-           c->left_col = w->left_col;
-         else
-           c->top_line = w->top_line;
-         size_window (child, size, width_p, nodelete_p,
-                      first_only, last_only);
-       }
-    }
-  else if (!NILP (*forward) && last_only)
-    {
-      /* Change the last in a series of siblings.  */
-      Lisp_Object last_child;
-      int child_size;
+         struct position pos;
+         struct buffer *obuf = current_buffer;
 
-      for (child = *forward; !NILP (child); child = c->next)
-       {
-         c = XWINDOW (child);
-         last_child = child;
+         Fset_buffer (w->buffer);
+         /* This computation used to temporarily move point, but that
+            can have unwanted side effects due to text properties.  */
+         pos = *vmotion (startpos, -top, w);
+
+         set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+         w->window_end_valid = Qnil;
+         w->start_at_line_beg = (pos.bytepos == BEGV_BYTE
+                                   || FETCH_BYTE (pos.bytepos - 1) == '\n');
+         /* We need to do this, so that the window-scroll-functions
+            get called.  */
+         w->optional_new_start = 1;
+
+         set_buffer_internal (obuf);
        }
-
-      child_size = WINDOW_TOTAL_SIZE (c, width_p);
-      size_window (last_child, size - old_size + child_size,
-                  width_p, nodelete_p, first_only, last_only);
-    }
-  else if (!NILP (*forward) && first_only)
-    {
-      /* Change the first in a series of siblings.  */
-      int child_size;
-
-      child = *forward;
-      c = XWINDOW (child);
-
-      if (width_p)
-       c->left_col = w->left_col;
-      else
-       c->top_line = w->top_line;
-
-      child_size = WINDOW_TOTAL_SIZE (c, width_p);
-      size_window (child, size - old_size + child_size,
-                  width_p, nodelete_p, first_only, last_only);
     }
-  else if (!NILP (*forward))
-    {
-      int fixed_size, each, extra, n;
-      int resize_fixed_p, nfixed;
-      int last_pos, first_pos, nchildren, total;
-      int *new_sizes = NULL;
-
-      /* Determine the fixed-size portion of this window, and the
-        number of child windows.  */
-      fixed_size = nchildren = nfixed = total = 0;
-      for (child = *forward; !NILP (child); child = c->next, ++nchildren)
-       {
-         int child_size;
-
-         c = XWINDOW (child);
-         child_size = WINDOW_TOTAL_SIZE (c, width_p);
-         total += child_size;
-
-         if (window_fixed_size_p (c, width_p, 0))
-           {
-             fixed_size += child_size;
-             ++nfixed;
-           }
-       }
-
-      /* If the new size is smaller than fixed_size, or if there
-        aren't any resizable windows, allow resizing fixed-size
-        windows.  */
-      resize_fixed_p = nfixed == nchildren || size < fixed_size;
-
-      /* Compute how many lines/columns to add/remove to each child.  The
-        value of extra takes care of rounding errors.  */
-      n = resize_fixed_p ? nchildren : nchildren - nfixed;
-      if (size < total && n > 1)
-        new_sizes = shrink_windows (total, size, nchildren, n,
-                                    resize_fixed_p, *forward, width_p,
-                                   nodelete_p == 2);
-      else
-        {
-          each = (size - total) / n;
-          extra = (size - total) - n * each;
-        }
-
-      /* Compute new children heights and edge positions.  */
-      first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
-      last_pos = first_pos;
-      for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
-       {
-         int new_size, old_size;
-
-         c = XWINDOW (child);
-         old_size = WINDOW_TOTAL_SIZE (c, width_p);
-         new_size = old_size;
 
-         /* The top or left edge position of this child equals the
-            bottom or right edge of its predecessor.  */
-         if (width_p)
-           c->left_col = make_number (last_pos);
-         else
-           c->top_line = make_number (last_pos);
-
-         /* If this child can be resized, do it.  */
-         if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
-           {
-             new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
-             extra = 0;
-           }
-
-         /* Set new size.  Note that size_window also propagates
-            edge positions to children, so it's not a no-op if we
-            didn't change the child's size.  */
-         size_window (child, new_size, width_p, 1, first_only, last_only);
-
-         /* Remember the bottom/right edge position of this child; it
-            will be used to set the top/left edge of the next child.  */
-          last_pos += new_size;
-       }
-
-      xfree (new_sizes);
-
-      /* We should have covered the parent exactly with child windows.  */
-      xassert (size == last_pos - first_pos);
+  adjust_glyphs (f);
+  UNBLOCK_INPUT;
 
-      /* Now delete any children that became too small.  */
-      if (nodelete_p != 1)
-       for (child = *forward; !NILP (child); child = c->next)
-         {
-           int child_size;
+  run_window_configuration_change_hook (f);
 
-           c = XWINDOW (child);
-           child_size = WINDOW_TOTAL_SIZE (c, width_p);
-           size_window (child, child_size, width_p, nodelete_p,
-                        first_only, last_only);
-         }
-    }
+  return Qnil;
 }
 
-/* Set WINDOW's height to HEIGHT, and recursively change the height of
-   WINDOW's children.  NODELETE zero means windows that have become
-   smaller than window-min-height in the process may be deleted.
-   NODELETE 1 means never delete windows that become too small in the
-   process.  (The caller should check later and do so if appropriate.)
-   NODELETE 2 means delete only windows that have become too small to be
-   displayed correctly.  */
 
 void
-set_window_height (window, height, nodelete)
-     Lisp_Object window;
-     int height;
-     int nodelete;
+replace_buffer_in_windows (Lisp_Object buffer)
 {
-  size_window (window, height, 0, nodelete, 0, 0);
+  call1 (Qreplace_buffer_in_windows, buffer);
 }
 
-/* Set WINDOW's width to WIDTH, and recursively change the width of
-   WINDOW's children.  NODELETE zero means windows that have become
-   smaller than window-min-width in the process may be deleted.
-   NODELETE 1 means never delete windows that become too small in the
-   process.  (The caller should check later and do so if appropriate.)
-   NODELETE 2 means delete only windows that have become too small to be
-   displayed correctly.  */
+
+/* Safely replace BUFFER with some other buffer in all windows of all
+   frames, even those on other keyboards.  */
 
 void
-set_window_width (window, width, nodelete)
-     Lisp_Object window;
-     int width;
-     int nodelete;
+replace_buffer_in_windows_safely (Lisp_Object buffer)
 {
-  size_window (window, width, 1, nodelete, 0, 0);
-}
+  Lisp_Object tail, frame;
 
-/* Change window heights in windows rooted in WINDOW by N lines.  */
+  /* A single call to window_loop won't do the job because it only
+     considers frames on the current keyboard.  So loop manually over
+     frames, and handle each one.  */
+  FOR_EACH_FRAME (tail, frame)
+    window_loop (REPLACE_BUFFER_IN_WINDOWS_SAFELY, buffer, 1, frame);
+}
+\f
+/* If *ROWS or *COLS are too small a size for FRAME, set them to the
+   minimum allowable size.  */
 
 void
-change_window_heights (window, n)
-     Lisp_Object window;
-     int n;
+check_frame_size (FRAME_PTR frame, int *rows, int *cols)
 {
-  struct window *w = XWINDOW (window);
+  /* For height, we have to see:
+     how many windows the frame has at minimum (one or two),
+     and whether it has a menu bar or other special stuff at the top.  */
+  int min_height
+    = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
+       ? MIN_SAFE_WINDOW_HEIGHT
+       : 2 * MIN_SAFE_WINDOW_HEIGHT);
+
+  if (FRAME_TOP_MARGIN (frame) > 0)
+    min_height += FRAME_TOP_MARGIN (frame);
 
-  XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
-  XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
+  if (*rows < min_height)
+    *rows = min_height;
+  if (*cols  < MIN_SAFE_WINDOW_WIDTH)
+    *cols = 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_cols = (WINDOW_TOTAL_COLS (w)
+                 - WINDOW_FRINGE_COLS (w)
+                 - WINDOW_SCROLL_BAR_COLS (w));
+  int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
+                    + WINDOW_RIGHT_MARGIN_COLS (w));
 
-  if (INTEGERP (w->orig_top_line))
-    XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
-  if (INTEGERP (w->orig_total_lines))
-    XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
+  if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
+    return 1;
 
-  /* Handle just the top child in a vertical split.  */
-  if (!NILP (w->vchild))
-    change_window_heights (w->vchild, n);
+  if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
+    return 0;
 
-  /* Adjust all children in a horizontal split.  */
-  for (window = w->hchild; !NILP (window); window = w->next)
+  /* Window's text area is too narrow, but reducing the window
+     margins will fix that.  */
+  margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
+  if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
     {
-      w = XWINDOW (window);
-      change_window_heights (window, n);
+      if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
+       w->left_margin_cols = w->right_margin_cols
+         = make_number (margin_cols/2);
+      else
+       w->right_margin_cols = make_number (margin_cols);
     }
+  else
+    w->left_margin_cols = make_number (margin_cols);
+  return 1;
 }
-
 \f
-int window_select_count;
-
-EXFUN (Fset_window_fringes, 4);
-EXFUN (Fset_window_scroll_bars, 4);
-
+static Lisp_Object Fset_window_margins (Lisp_Object, Lisp_Object, Lisp_Object);
+static Lisp_Object Fset_window_fringes (Lisp_Object, Lisp_Object, Lisp_Object,
+                                       Lisp_Object);
+static Lisp_Object Fset_window_scroll_bars (Lisp_Object, Lisp_Object,
+                                           Lisp_Object, Lisp_Object);
+static Lisp_Object Fset_window_vscroll (Lisp_Object, Lisp_Object, Lisp_Object);
+
+/* The following three routines are needed for running a window's
+   configuration change hook.  */
 static void
 run_funs (Lisp_Object funs)
 {
@@ -3379,26 +2891,31 @@ run_funs (Lisp_Object funs)
       call0 (XCAR (funs));
 }
 
-static Lisp_Object select_window_norecord (Lisp_Object window);
-static Lisp_Object select_frame_norecord (Lisp_Object frame);
+static Lisp_Object
+select_window_norecord (Lisp_Object window)
+{
+  return WINDOW_LIVE_P (window)
+    ? Fselect_window (window, Qt) : selected_window;
+}
+
+static Lisp_Object
+select_frame_norecord (Lisp_Object frame)
+{
+  return FRAME_LIVE_P (XFRAME (frame))
+    ? Fselect_frame (frame, Qt) : selected_frame;
+}
 
 void
 run_window_configuration_change_hook (struct frame *f)
 {
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object frame, global_wcch
     = Fdefault_value (Qwindow_configuration_change_hook);
   XSETFRAME (frame, f);
 
-  if (NILP (Vrun_hooks))
+  if (NILP (Vrun_hooks) || !NILP (inhibit_lisp_code))
     return;
 
-  if (SELECTED_FRAME () != f)
-    {
-      record_unwind_protect (select_frame_norecord, Fselected_frame ());
-      Fselect_frame (frame, Qt);
-    }
-
   /* Use the right buffer.  Matters when running the local hooks.  */
   if (current_buffer != XBUFFER (Fwindow_buffer (Qnil)))
     {
@@ -3406,6 +2923,12 @@ run_window_configuration_change_hook (struct frame *f)
       Fset_buffer (Fwindow_buffer (Qnil));
     }
 
+  if (SELECTED_FRAME () != f)
+    {
+      record_unwind_protect (select_frame_norecord, Fselected_frame ());
+      select_frame_norecord (frame);
+    }
+
   /* Look for buffer-local values.  */
   {
     Lisp_Object windows = Fwindow_list (frame, Qlambda, Qnil);
@@ -3416,12 +2939,12 @@ run_window_configuration_change_hook (struct frame *f)
        if (!NILP (Flocal_variable_p (Qwindow_configuration_change_hook,
                                      buffer)))
          {
-           int count = SPECPDL_INDEX ();
+           ptrdiff_t inner_count = SPECPDL_INDEX ();
            record_unwind_protect (select_window_norecord, Fselected_window ());
            select_window_norecord (window);
            run_funs (Fbuffer_local_value (Qwindow_configuration_change_hook,
                                           buffer));
-           unbind_to (count, Qnil);
+           unbind_to (inner_count, Qnil);
          }
       }
   }
@@ -3430,6 +2953,16 @@ run_window_configuration_change_hook (struct frame *f)
   unbind_to (count, Qnil);
 }
 
+DEFUN ("run-window-configuration-change-hook", Frun_window_configuration_change_hook,
+       Srun_window_configuration_change_hook, 1, 1, 0,
+       doc: /* Run `window-configuration-change-hook' for FRAME.  */)
+     (Lisp_Object frame)
+{
+  CHECK_LIVE_FRAME (frame);
+  run_window_configuration_change_hook (XFRAME (frame));
+  return Qnil;
+}
+
 /* Make WINDOW display BUFFER as its contents.  RUN_HOOKS_P non-zero
    means it's allowed to run hooks.  See make_frame for a case where
    it's not allowed.  KEEP_MARGINS_P non-zero means that the current
@@ -3437,31 +2970,29 @@ run_window_configuration_change_hook (struct frame *f)
    reset from the buffer's local settings.  */
 
 void
-set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
-     Lisp_Object window, buffer;
-     int run_hooks_p, keep_margins_p;
+set_window_buffer (Lisp_Object window, Lisp_Object buffer, int run_hooks_p, int keep_margins_p)
 {
   struct window *w = XWINDOW (window);
   struct buffer *b = XBUFFER (buffer);
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
   int samebuf = EQ (buffer, w->buffer);
 
   w->buffer = buffer;
 
   if (EQ (window, selected_window))
-    b->last_selected_window = window;
+    BVAR (b, last_selected_window) = window;
 
   /* Let redisplay errors through.  */
   b->display_error_modiff = 0;
 
   /* Update time stamps of buffer display.  */
-  if (INTEGERP (b->display_count))
-    XSETINT (b->display_count, XINT (b->display_count) + 1);
-  b->display_time = Fcurrent_time ();
+  if (INTEGERP (BVAR (b, display_count)))
+    XSETINT (BVAR (b, display_count), XINT (BVAR (b, display_count)) + 1);
+  BVAR (b, display_time) = Fcurrent_time ();
 
   XSETFASTINT (w->window_end_pos, 0);
   XSETFASTINT (w->window_end_vpos, 0);
-  bzero (&w->last_cursor, sizeof w->last_cursor);
+  memset (&w->last_cursor, 0, sizeof w->last_cursor);
   w->window_end_valid = Qnil;
   if (!(keep_margins_p && samebuf))
     { /* If we're not actually changing the buffer, don't reset hscroll and
@@ -3478,8 +3009,8 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
       set_marker_restricted (w->start,
                             make_number (b->last_window_start),
                             buffer);
-      w->start_at_line_beg = Qnil;
-      w->force_start = Qnil;
+      w->start_at_line_beg = 0;
+      w->force_start = 0;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
     }
@@ -3510,18 +3041,18 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
       w->left_margin_cols = w->right_margin_cols = Qnil;
 
       Fset_window_fringes (window,
-                          b->left_fringe_width, b->right_fringe_width,
-                          b->fringes_outside_margins);
+                          BVAR (b, left_fringe_width), BVAR (b, right_fringe_width),
+                          BVAR (b, fringes_outside_margins));
 
       Fset_window_scroll_bars (window,
-                              b->scroll_bar_width,
-                              b->vertical_scroll_bar_type, Qnil);
+                              BVAR (b, scroll_bar_width),
+                              BVAR (b, vertical_scroll_bar_type), Qnil);
 
       w->left_margin_cols = save_left;
       w->right_margin_cols = save_right;
 
       Fset_window_margins (window,
-                          b->left_margin_cols, b->right_margin_cols);
+                          BVAR (b, left_margin_cols), BVAR (b, right_margin_cols));
     }
 
   if (run_hooks_p)
@@ -3535,14 +3066,15 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
   unbind_to (count, Qnil);
 }
 
-
 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
        doc: /* Make WINDOW display BUFFER-OR-NAME as its contents.
-WINDOW defaults to the selected window.  BUFFER-OR-NAME must be a buffer
-or the name of an existing buffer.  Optional third argument KEEP-MARGINS
-non-nil means that WINDOW's current display margins, fringe widths, and
-scroll bar settings are preserved; the default is to reset these from
-the local settings for BUFFER-OR-NAME or the frame defaults.  Return nil.
+WINDOW has to be a live window and defaults to the selected one.
+BUFFER-OR-NAME must be a buffer or the name of an existing buffer.
+
+Optional third argument KEEP-MARGINS non-nil means that WINDOW's current
+display margins, fringe widths, and scroll bar settings are preserved;
+the default is to reset these from the local settings for BUFFER-OR-NAME
+or the frame defaults.  Return nil.
 
 This function throws an error when WINDOW is strongly dedicated to its
 buffer (that is `window-dedicated-p' returns t for WINDOW) and does not
@@ -3550,8 +3082,7 @@ already display BUFFER-OR-NAME.
 
 This function runs `window-scroll-functions' before running
 `window-configuration-change-hook'.  */)
-     (window, buffer_or_name, keep_margins)
-     register Lisp_Object window, buffer_or_name, keep_margins;
+  (register Lisp_Object window, Lisp_Object buffer_or_name, Lisp_Object keep_margins)
 {
   register Lisp_Object tem, buffer;
   register struct window *w = decode_window (window);
@@ -3559,7 +3090,7 @@ This function runs `window-scroll-functions' before running
   XSETWINDOW (window, w);
   buffer = Fget_buffer (buffer_or_name);
   CHECK_BUFFER (buffer);
-  if (NILP (XBUFFER (buffer)->name))
+  if (NILP (BVAR (XBUFFER (buffer), name)))
     error ("Attempt to display deleted buffer");
 
   tem = w->buffer;
@@ -3569,141 +3100,29 @@ This function runs `window-scroll-functions' before running
     /* w->buffer is t when the window is first being set up.  */
     {
       if (!EQ (tem, buffer))
-       if (EQ (w->dedicated, Qt))
-         error ("Window is dedicated to `%s'", SDATA (XBUFFER (tem)->name));
-       else
-         w->dedicated = Qnil;
+       {
+         if (EQ (w->dedicated, Qt))
+           /* WINDOW is strongly dedicated to its buffer, signal an
+              error.  */
+           error ("Window is dedicated to `%s'", SDATA (BVAR (XBUFFER (tem), name)));
+         else
+           /* WINDOW is weakly dedicated to its buffer, reset
+              dedication.  */
+           w->dedicated = Qnil;
+
+         call1 (Qrecord_window_buffer, window);
+       }
 
       unshow_buffer (w);
     }
 
   set_window_buffer (window, buffer, 1, !NILP (keep_margins));
-  return Qnil;
-}
-
-/* If select_window is called with inhibit_point_swap non-zero it will
-   not store point of the old selected window's buffer back into that
-   window's pointm slot.  This is needed by Fset_window_configuration to
-   avoid that the display routine is called with selected_window set to
-   Qnil causing a subsequent crash.  */
-
-static Lisp_Object
-select_window (window, norecord, inhibit_point_swap)
-     Lisp_Object window, norecord;
-     int inhibit_point_swap;
-{
-  register struct window *w;
-  register struct window *ow;
-  struct frame *sf;
-
-  CHECK_LIVE_WINDOW (window);
-
-  w = XWINDOW (window);
-  w->frozen_window_start_p = 0;
-
-  if (NILP (norecord))
-    {
-      ++window_select_count;
-      XSETFASTINT (w->use_time, window_select_count);
-    }
-
-  if (EQ (window, selected_window) && !inhibit_point_swap)
-    return window;
-
-  sf = SELECTED_FRAME ();
-  if (XFRAME (WINDOW_FRAME (w)) != sf)
-    {
-      XFRAME (WINDOW_FRAME (w))->selected_window = window;
-      /* Use this rather than Fhandle_switch_frame
-        so that FRAME_FOCUS_FRAME is moved appropriately as we
-        move around in the state where a minibuffer in a separate
-        frame is active.  */
-      Fselect_frame (WINDOW_FRAME (w), norecord);
-      /* Fselect_frame called us back so we've done all the work already.  */
-      eassert (EQ (window, selected_window));
-      return window;
-    }
-  else
-    sf->selected_window = window;
-
-  /* Store the current buffer's actual point into the
-     old selected window.  It belongs to that window,
-     and when the window is not selected, must be in the window.  */
-  if (!inhibit_point_swap)
-    {
-      ow = XWINDOW (selected_window);
-      if (! NILP (ow->buffer))
-       set_marker_both (ow->pointm, ow->buffer,
-                        BUF_PT (XBUFFER (ow->buffer)),
-                        BUF_PT_BYTE (XBUFFER (ow->buffer)));
-    }
-
-  selected_window = window;
-
-  if (NILP (norecord))
-    record_buffer (w->buffer);
-  Fset_buffer (w->buffer);
-
-  XBUFFER (w->buffer)->last_selected_window = window;
-
-  /* Go to the point recorded in the window.
-     This is important when the buffer is in more
-     than one window.  It also matters when
-     redisplay_window has altered point after scrolling,
-     because it makes the change only in the window.  */
-  {
-    register int new_point = marker_position (w->pointm);
-    if (new_point < BEGV)
-      SET_PT (BEGV);
-    else if (new_point > ZV)
-      SET_PT (ZV);
-    else
-      SET_PT (new_point);
-  }
-
-  windows_or_buffers_changed++;
-  return window;
-}
-
-
-/* Note that selected_window can be nil when this is called from
-   Fset_window_configuration.  */
-
-DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
-       doc: /* Select WINDOW.  Most editing will apply to WINDOW's buffer.
-If WINDOW is not already selected, make WINDOW's buffer current
-and make WINDOW the frame's selected window.  Return WINDOW.
-Optional second arg NORECORD non-nil means do not put this buffer
-at the front of the list of recently selected ones and do not
-make this window the most recently selected one.
-
-Note that the main editor command loop selects the buffer of the
-selected window before each command.  */)
-     (window, norecord)
-     register Lisp_Object window, norecord;
-{
-  return select_window (window, norecord, 0);
-}
-
-static Lisp_Object
-select_window_norecord (window)
-     Lisp_Object window;
-{
-  return WINDOW_LIVE_P (window)
-    ? Fselect_window (window, Qt) : selected_window;
-}
 
-static Lisp_Object
-select_frame_norecord (frame)
-     Lisp_Object frame;
-{
-  return FRAME_LIVE_P (XFRAME (frame))
-    ? Fselect_frame (frame, Qt) : selected_frame;
+  return Qnil;
 }
 \f
-Lisp_Object
-display_buffer (buffer, not_this_window_p, override_frame)
-     Lisp_Object buffer, not_this_window_p, override_frame;
+static Lisp_Object
+display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p, Lisp_Object override_frame)
 {
   return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
 }
@@ -3714,8 +3133,7 @@ DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
 If optional arg OBJECT is a window, force redisplay of that window only.
 If OBJECT is a buffer or buffer name, force redisplay of all windows
 displaying that buffer.  */)
-     (object)
-     Lisp_Object object;
+  (Lisp_Object object)
 {
   if (NILP (object))
     {
@@ -3728,7 +3146,7 @@ displaying that buffer.  */)
     {
       struct window *w = XWINDOW (object);
       mark_window_display_accurate (object, 0);
-      w->update_mode_line = Qt;
+      w->update_mode_line = 1;
       if (BUFFERP (w->buffer))
        XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
       ++update_mode_lines;
@@ -3737,7 +3155,7 @@ displaying that buffer.  */)
 
   if (STRINGP (object))
     object = Fget_buffer (object);
-  if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
+  if (BUFFERP (object) && !NILP (BVAR (XBUFFER (object), name)))
     {
       /* Walk all windows looking for buffer, and force update
         of each of those windows.  */
@@ -3754,23 +3172,19 @@ displaying that buffer.  */)
 
 
 void
-temp_output_buffer_show (buf)
-     register Lisp_Object buf;
+temp_output_buffer_show (register Lisp_Object buf)
 {
   register struct buffer *old = current_buffer;
   register Lisp_Object window;
   register struct window *w;
 
-  XBUFFER (buf)->directory = current_buffer->directory;
+  BVAR (XBUFFER (buf), directory) = BVAR (current_buffer, directory);
 
   Fset_buffer (buf);
   BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
   BEGV = BEG;
   ZV = Z;
   SET_PT (BEG);
-#if 0  /* rms: there should be no reason for this.  */
-  XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
-#endif
   set_buffer_internal (old);
 
   if (!NILP (Vtemp_buffer_show_function))
@@ -3790,35 +3204,43 @@ temp_output_buffer_show (buf)
 
       /* Run temp-buffer-show-hook, with the chosen window selected
         and its buffer current.  */
-
-      if (!NILP (Vrun_hooks)
-         && !NILP (Fboundp (Qtemp_buffer_show_hook))
-         && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
-       {
-         int count = SPECPDL_INDEX ();
-         Lisp_Object prev_window, prev_buffer;
-         prev_window = selected_window;
-         XSETBUFFER (prev_buffer, old);
-
-         /* Select the window that was chosen, for running the hook.
-            Note: Both Fselect_window and select_window_norecord may
-            set-buffer to the buffer displayed in the window,
-            so we need to save the current buffer.  --stef  */
-         record_unwind_protect (Fset_buffer, prev_buffer);
-         record_unwind_protect (select_window_norecord, prev_window);
-         Fselect_window (window, Qt);
-         Fset_buffer (w->buffer);
-         call1 (Vrun_hooks, Qtemp_buffer_show_hook);
-         unbind_to (count, Qnil);
-       }
+      {
+        ptrdiff_t count = SPECPDL_INDEX ();
+        Lisp_Object prev_window, prev_buffer;
+        prev_window = selected_window;
+        XSETBUFFER (prev_buffer, old);
+
+        /* Select the window that was chosen, for running the hook.
+           Note: Both Fselect_window and select_window_norecord may
+           set-buffer to the buffer displayed in the window,
+           so we need to save the current buffer.  --stef  */
+        record_unwind_protect (Fset_buffer, prev_buffer);
+        record_unwind_protect (select_window_norecord, prev_window);
+        Fselect_window (window, Qt);
+        Fset_buffer (w->buffer);
+        Frun_hooks (1, &Qtemp_buffer_show_hook);
+        unbind_to (count, Qnil);
+      }
     }
 }
+
+DEFUN ("internal-temp-output-buffer-show",
+       Ftemp_output_buffer_show, Stemp_output_buffer_show,
+       1, 1, 0,
+       doc: /* Internal function for `with-output-to-temp-buffer'.  */)
+     (Lisp_Object buf)
+{
+  temp_output_buffer_show (buf);
+  return Qnil;
+}
 \f
+/* Make new window, have it replace WINDOW in window-tree, and make
+   WINDOW its only vertical child (HORFLAG 1 means make WINDOW its only
+   horizontal child).   */
 static void
-make_dummy_parent (window)
-     Lisp_Object window;
+make_parent_window (Lisp_Object window, int horflag)
 {
-  Lisp_Object new;
+  Lisp_Object parent;
   register struct window *o, *p;
   int i;
 
@@ -3826,909 +3248,897 @@ make_dummy_parent (window)
   p = allocate_window ();
   for (i = 0; i < VECSIZE (struct window); ++i)
     ((struct Lisp_Vector *) p)->contents[i]
-      = ((struct Lisp_Vector *)o)->contents[i];
-  XSETWINDOW (new, p);
+      = ((struct Lisp_Vector *) o)->contents[i];
+  XSETWINDOW (parent, p);
 
   ++sequence_number;
   XSETFASTINT (p->sequence_number, sequence_number);
 
-  /* Put new into window structure in place of window */
-  replace_window (window, new);
+  replace_window (window, parent, 1);
 
   o->next = Qnil;
   o->prev = Qnil;
-  o->vchild = Qnil;
-  o->hchild = Qnil;
-  o->parent = new;
+  o->parent = parent;
 
+  p->hchild = horflag ? window : Qnil;
+  p->vchild = horflag ? Qnil : window;
   p->start = Qnil;
   p->pointm = Qnil;
   p->buffer = Qnil;
+  p->combination_limit = Qnil;
+  p->window_parameters = Qnil;
 }
 
-DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
-       doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
-WINDOW defaults to selected one and SIZE to half its size.
-If optional third arg HORIZONTAL is non-nil, split side by side and put
-SIZE columns in the first of the pair.  In that case, SIZE includes that
-window's scroll bar, or the divider column to its right.
-Interactively, all arguments are nil.
-Returns the newly created window (which is the lower or rightmost one).
-The upper or leftmost window is the original one, and remains selected
-if it was selected before.
-
-See Info node `(elisp)Splitting Windows' for more details and examples.  */)
-     (window, size, horizontal)
-     Lisp_Object window, size, horizontal;
+/* Make new window from scratch.  */
+Lisp_Object
+make_window (void)
 {
-  register Lisp_Object new;
-  register struct window *o, *p;
-  FRAME_PTR fo;
-  register int size_int;
-
-  if (NILP (window))
-    window = selected_window;
-  else
-    CHECK_LIVE_WINDOW (window);
+  Lisp_Object window;
+  register struct window *w;
 
-  o = XWINDOW (window);
-  fo = XFRAME (WINDOW_FRAME (o));
+  w = allocate_window ();
+  /* Initialize all Lisp data.  */
+  w->frame = Qnil;
+  w->mini = 0;
+  w->next = w->prev = w->hchild = w->vchild = w->parent = Qnil;
+  XSETFASTINT (w->left_col, 0);
+  XSETFASTINT (w->top_line, 0);
+  XSETFASTINT (w->total_lines, 0);
+  XSETFASTINT (w->total_cols, 0);
+  w->normal_lines = make_float (1.0);
+  w->normal_cols = make_float (1.0);
+  XSETFASTINT (w->new_total, 0);
+  XSETFASTINT (w->new_normal, 0);
+  w->buffer = Qnil;
+  w->start = Fmake_marker ();
+  w->pointm = Fmake_marker ();
+  w->force_start = w->optional_new_start = 0;
+  XSETFASTINT (w->hscroll, 0);
+  XSETFASTINT (w->min_hscroll, 0);
+  XSETFASTINT (w->use_time, 0);
+  ++sequence_number;
+  XSETFASTINT (w->sequence_number, sequence_number);
+  w->temslot = w->last_modified = w->last_overlay_modified = Qnil;
+  XSETFASTINT (w->last_point, 0);
+  w->last_had_star = 0;
+  w->vertical_scroll_bar = Qnil;
+  w->left_margin_cols = w->right_margin_cols = Qnil;
+  w->left_fringe_width = w->right_fringe_width = Qnil;
+  w->fringes_outside_margins = Qnil;
+  w->scroll_bar_width = Qnil;
+  w->vertical_scroll_bar_type = Qt;
+  XSETFASTINT (w->window_end_pos, 0);
+  XSETFASTINT (w->window_end_vpos, 0);
+  w->window_end_valid = w->display_table = Qnil;
+  w->update_mode_line = w->start_at_line_beg = 0;
+  w->dedicated = Qnil;
+  w->base_line_number = w->base_line_pos = w->region_showing = Qnil;
+  w->column_number_displayed = w->redisplay_end_trigger = Qnil;
+  w->combination_limit = w->window_parameters = Qnil;
+  w->prev_buffers = w->next_buffers = Qnil;
+  /* Initialize non-Lisp data.  */
+  w->desired_matrix = w->current_matrix = 0;
+  w->nrows_scale_factor = w->ncols_scale_factor = 1;
+  memset (&w->cursor, 0, sizeof (w->cursor));
+  memset (&w->last_cursor, 0, sizeof (w->last_cursor));
+  memset (&w->phys_cursor, 0, sizeof (w->phys_cursor));
+  w->phys_cursor_type = -1;
+  w->phys_cursor_width = -1;
+  w->phys_cursor_on_p = 0;
+  w->last_cursor_off_p = w->cursor_off_p = 0;
+  w->must_be_updated_p = 0;
+  w->pseudo_window_p = 0;
+  w->frozen_window_start_p = 0;
+  w->vscroll = 0;
+  /* Reset window_list.  */
+  Vwindow_list = Qnil;
+  /* Return window.  */
+  XSETWINDOW (window, w);
+  return window;
+}
+\f
+DEFUN ("set-window-new-total", Fset_window_new_total, Sset_window_new_total, 2, 3, 0,
+       doc: /* Set new total size of WINDOW to SIZE.
+Return SIZE.
 
-  if (NILP (size))
-    {
-      if (!NILP (horizontal))
-       /* Calculate the size of the left-hand window, by dividing
-          the usable space in columns by two.
-          We round up, since the left-hand window may include
-          a dividing line, while the right-hand may not.  */
-       size_int = (XFASTINT (o->total_cols) + 1) >> 1;
-      else
-       size_int = XFASTINT (o->total_lines) >> 1;
-    }
-  else
-    {
-      CHECK_NUMBER (size);
-      size_int = XINT (size);
-    }
+Optional argument ADD non-nil means add SIZE to the new total size of
+WINDOW and return the sum.
 
-  if (MINI_WINDOW_P (o))
-    error ("Attempt to split minibuffer window");
-  else if (window_fixed_size_p (o, !NILP (horizontal), 0))
-    error ("Attempt to split fixed-size window");
+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_any_window (window);
 
-  if (NILP (horizontal))
-    {
-      int window_safe_height = window_min_size_2 (o, 0, 0);
-
-      if (size_int < window_safe_height)
-       error ("Window height %d too small (after splitting)", size_int);
-      if (size_int + window_safe_height > XFASTINT (o->total_lines))
-       error ("Window height %d too small (after splitting)",
-              XFASTINT (o->total_lines) - size_int);
-      if (NILP (o->parent)
-         || NILP (XWINDOW (o->parent)->vchild))
-       {
-         make_dummy_parent (window);
-         new = o->parent;
-         XWINDOW (new)->vchild = window;
-       }
-    }
+  CHECK_NUMBER (size);
+  if (NILP (add))
+    XSETINT (w->new_total, XINT (size));
   else
-    {
-      int window_safe_width = window_min_size_2 (o, 1, 0);
-
-      if (size_int < window_safe_width)
-       error ("Window width %d too small (after splitting)", size_int);
-      if (size_int + window_safe_width > XFASTINT (o->total_cols))
-       error ("Window width %d too small (after splitting)",
-              XFASTINT (o->total_cols) - size_int);
-      if (NILP (o->parent)
-         || NILP (XWINDOW (o->parent)->hchild))
-       {
-         make_dummy_parent (window);
-         new = o->parent;
-         XWINDOW (new)->hchild = window;
-       }
-    }
+    XSETINT (w->new_total, XINT (w->new_total) + XINT (size));
 
-  /* Now we know that window's parent is a vertical combination
-     if we are dividing vertically, or a horizontal combination
-     if we are making side-by-side windows */
-
-  windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
-  new = make_window ();
-  p = XWINDOW (new);
-
-  p->frame = o->frame;
-  p->next = o->next;
-  if (!NILP (p->next))
-    XWINDOW (p->next)->prev = new;
-  p->prev = window;
-  o->next = new;
-  p->parent = o->parent;
-  p->buffer = Qt;
-  p->window_end_valid = Qnil;
-  bzero (&p->last_cursor, sizeof p->last_cursor);
-
-  /* Duplicate special geometry settings.  */
-
-  p->left_margin_cols = o->left_margin_cols;
-  p->right_margin_cols = o->right_margin_cols;
-  p->left_fringe_width = o->left_fringe_width;
-  p->right_fringe_width = o->right_fringe_width;
-  p->fringes_outside_margins = o->fringes_outside_margins;
-  p->scroll_bar_width = o->scroll_bar_width;
-  p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
-
-  /* Apportion the available frame space among the two new windows */
-
-  if (!NILP (horizontal))
-    {
-      p->total_lines = o->total_lines;
-      p->top_line = o->top_line;
-      XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
-      XSETFASTINT (o->total_cols, size_int);
-      XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
-      adjust_window_margins (p);
-      adjust_window_margins (o);
-    }
-  else
-    {
-      p->left_col = o->left_col;
-      p->total_cols = o->total_cols;
-      XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
-      XSETFASTINT (o->total_lines, size_int);
-      XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
-    }
+  return w->new_total;
+}
 
-  /* Adjust glyph matrices.  */
-  adjust_glyphs (fo);
+DEFUN ("set-window-new-normal", Fset_window_new_normal, Sset_window_new_normal, 1, 2, 0,
+       doc: /* Set new normal size of WINDOW to SIZE.
+Return SIZE.
 
-  Fset_window_buffer (new, o->buffer, Qt);
-  return new;
-}
-\f
-DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
-       doc: /* Make selected window SIZE lines taller.
-Interactively, if no argument is given, make the selected window one
-line taller.  If optional argument HORIZONTAL is non-nil, make selected
-window wider by SIZE columns.  If SIZE is negative, shrink the window by
--SIZE lines or columns.  Return nil.
-
-This function can delete windows if they get too small.  The size of
-fixed size windows is not altered by this function.  */)
-     (size, horizontal)
-     Lisp_Object size, horizontal;
+Note: This function does not operate on any child windows of WINDOW.  */)
+     (Lisp_Object window, Lisp_Object size)
 {
-  CHECK_NUMBER (size);
-  enlarge_window (selected_window, XINT (size), !NILP (horizontal));
-
-  run_window_configuration_change_hook (SELECTED_FRAME ());
+  struct window *w = decode_any_window (window);
 
-  return Qnil;
+  w->new_normal = size;
+  return w->new_normal;
 }
 
-DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
-       doc: /* Make selected window SIZE lines smaller.
-Interactively, if no argument is given, make the selected window one
-line smaller.  If optional argument HORIZONTAL is non-nil, make the
-window narrower by SIZE columns.  If SIZE is negative, enlarge selected
-window by -SIZE lines or columns.  Return nil.
+/* Return 1 if setting w->total_lines (w->total_cols if HORFLAG is
+   non-zero) to w->new_total would result in correct heights (widths)
+   for window W and recursively all child windows of W.
 
-This function can delete windows if they get too small.  The size of
-fixed size windows is not altered by this function. */)
-     (size, horizontal)
-     Lisp_Object size, horizontal;
+   Note: This function does not check any of `window-fixed-size-p',
+   `window-min-height' or `window-min-width'.  It does check that window
+   sizes do not drop below one line (two columns). */
+static int
+window_resize_check (struct window *w, int horflag)
 {
-  CHECK_NUMBER (size);
-  enlarge_window (selected_window, -XINT (size), !NILP (horizontal));
-
-  run_window_configuration_change_hook (SELECTED_FRAME ());
+  struct window *c;
 
-  return Qnil;
+  if (!NILP (w->vchild))
+    /* W is a vertical combination.  */
+    {
+      c = XWINDOW (w->vchild);
+      if (horflag)
+       /* All child windows of W must have the same width as W.  */
+       {
+         while (c)
+           {
+             if ((XINT (c->new_total) != XINT (w->new_total))
+                 || !window_resize_check (c, horflag))
+               return 0;
+             c = NILP (c->next) ? 0 : XWINDOW (c->next);
+           }
+         return 1;
+       }
+      else
+       /* The sum of the heights of the child windows of W must equal
+          W's height.  */
+       {
+         int sum_of_sizes = 0;
+         while (c)
+           {
+             if (!window_resize_check (c, horflag))
+               return 0;
+             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+             c = NILP (c->next) ? 0 : XWINDOW (c->next);
+           }
+         return (sum_of_sizes == XINT (w->new_total));
+       }
+    }
+  else if (!NILP (w->hchild))
+    /* W is a horizontal combination.  */
+    {
+      c = XWINDOW (w->hchild);
+      if (horflag)
+       /* The sum of the widths of the child windows of W must equal W's
+          width.  */
+       {
+         int sum_of_sizes = 0;
+         while (c)
+           {
+             if (!window_resize_check (c, horflag))
+               return 0;
+             sum_of_sizes = sum_of_sizes + XINT (c->new_total);
+             c = NILP (c->next) ? 0 : XWINDOW (c->next);
+           }
+         return (sum_of_sizes == XINT (w->new_total));
+       }
+      else
+       /* All child windows of W must have the same height as W.  */
+       {
+         while (c)
+           {
+             if ((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_total) >= (horflag ? 2 : 1);
 }
 
-int
-window_height (window)
-     Lisp_Object window;
-{
-  register struct window *p = XWINDOW (window);
-  return WINDOW_TOTAL_LINES (p);
-}
+/* Set w->total_lines (w->total_cols if HORIZONTAL is non-zero) to
+   w->new_total for window W and recursively all child windows of W.
+   Also calculate and assign the new vertical (horizontal) start
+   positions of each of these windows.
 
-int
-window_width (window)
-     Lisp_Object window;
+   This function does not perform any error checks.  Make sure you have
+   run window_resize_check on W before applying this function.  */
+static void
+window_resize_apply (struct window *w, int horflag)
 {
-  register struct window *p = XWINDOW (window);
-  return WINDOW_TOTAL_COLS (p);
-}
-
-
-#define CURBEG(w) \
-  *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
-
-#define CURSIZE(w) \
-  *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
+  struct window *c;
+  int pos;
 
+  /* Note: Assigning new_normal requires that the new total size of the
+     parent window has been set *before*.  */
+  if (horflag)
+    {
+      w->total_cols = w->new_total;
+      if (NUMBERP (w->new_normal))
+       w->normal_cols = w->new_normal;
 
-/* Enlarge WINDOW by DELTA.  HORIZ_FLAG nonzero means enlarge it
-   horizontally; zero means do it vertically.
+      pos = XINT (w->left_col);
+    }
+  else
+    {
+      w->total_lines = w->new_total;
+      if (NUMBERP (w->new_normal))
+       w->normal_lines = w->new_normal;
 
-   Siblings of the selected window are resized to fulfill the size
-   request.  If they become too small in the process, they may be
-   deleted.  */
+      pos = XINT (w->top_line);
+    }
 
-static void
-enlarge_window (window, delta, horiz_flag)
-     Lisp_Object window;
-     int delta, horiz_flag;
-{
-  Lisp_Object parent, next, prev;
-  struct window *p;
-  Lisp_Object *sizep;
-  int maximum;
-  int (*sizefun) P_ ((Lisp_Object))
-    = horiz_flag ? window_width : window_height;
-  void (*setsizefun) P_ ((Lisp_Object, int, int))
-    = (horiz_flag ? set_window_width : set_window_height);
-
-  /* Give up if this window cannot be resized.  */
-  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
-    error ("Window is not resizable");
-
-  /* Find the parent of the selected window.  */
-  while (1)
+  if (!NILP (w->vchild))
+    /* W is a vertical combination.  */
     {
-      p = XWINDOW (window);
-      parent = p->parent;
-
-      if (NILP (parent))
+      c = XWINDOW (w->vchild);
+      while (c)
        {
-         if (horiz_flag)
-           error ("No other window to side of this one");
-         break;
+         if (horflag)
+           XSETFASTINT (c->left_col, pos);
+         else
+           XSETFASTINT (c->top_line, pos);
+         window_resize_apply (c, horflag);
+         if (!horflag)
+           pos = pos + XINT (c->total_lines);
+         c = NILP (c->next) ? 0 : XWINDOW (c->next);
+       }
+    }
+  else if (!NILP (w->hchild))
+    /* W is a horizontal combination.  */
+    {
+      c = XWINDOW (w->hchild);
+      while (c)
+       {
+         if (horflag)
+           XSETFASTINT (c->left_col, pos);
+         else
+           XSETFASTINT (c->top_line, pos);
+         window_resize_apply (c, horflag);
+         if (horflag)
+           pos = pos + XINT (c->total_cols);
+         c = NILP (c->next) ? 0 : XWINDOW (c->next);
        }
-
-      if (horiz_flag
-         ? !NILP (XWINDOW (parent)->hchild)
-         : !NILP (XWINDOW (parent)->vchild))
-       break;
-
-      window = parent;
     }
 
-  sizep = &CURSIZE (window);
+  /* Clear out some redisplay caches.  */
+  XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
+}
 
-  {
-    register int maxdelta;
-
-    /* Compute the maximum size increment this window can have.  */
-
-    maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
-               /* This is a main window followed by a minibuffer.  */
-               : !NILP (p->next) ? ((*sizefun) (p->next)
-                                    - window_min_size (XWINDOW (p->next),
-                                                       horiz_flag, 0, 0, 0))
-               /* This is a minibuffer following a main window.  */
-               : !NILP (p->prev) ? ((*sizefun) (p->prev)
-                                    - window_min_size (XWINDOW (p->prev),
-                                                       horiz_flag, 0, 0, 0))
-               /* This is a frame with only one window, a minibuffer-only
-                  or a minibufferless frame.  */
-               : (delta = 0));
-
-    if (delta > maxdelta)
-      /* This case traps trying to make the minibuffer
-        the full frame, or make the only window aside from the
-        minibuffer the full frame.  */
-      delta = maxdelta;
-  }
 
-  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window),
-                                              horiz_flag, 0, 0, 0))
-    {
-      delete_window (window);
-      return;
-    }
+DEFUN ("window-resize-apply", Fwindow_resize_apply, Swindow_resize_apply, 1, 2, 0,
+       doc: /* Apply requested size values for window-tree of FRAME.
+Optional argument HORIZONTAL omitted or nil means apply requested height
+values.  HORIZONTAL non-nil means apply requested width values.
 
-  if (delta == 0)
-    return;
+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.
 
-  /* Find the total we can get from other siblings without deleting them.  */
-  maximum = 0;
-  for (next = p->next; WINDOWP (next); next = XWINDOW (next)->next)
-    maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
-                                                   horiz_flag, 0, 0, 0);
-  for (prev = p->prev; WINDOWP (prev); prev = XWINDOW (prev)->prev)
-    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
-                                                   horiz_flag, 0, 0, 0);
-
-  /* If we can get it all from them without deleting them, do so.  */
-  if (delta <= maximum)
-    {
-      Lisp_Object first_unaffected;
-      Lisp_Object first_affected;
-      int fixed_p;
-
-      next = p->next;
-      prev = p->prev;
-      first_affected = window;
-      /* Look at one sibling at a time,
-        moving away from this window in both directions alternately,
-        and take as much as we can get without deleting that sibling.  */
-      while (delta != 0
-            && (!NILP (next) || !NILP (prev)))
-       {
-         if (! NILP (next))
-           {
-             int this_one = ((*sizefun) (next)
-                             - window_min_size (XWINDOW (next), horiz_flag,
-                                                0, 0, &fixed_p));
-             if (!fixed_p)
-               {
-                 if (this_one > delta)
-                   this_one = delta;
+Note: This function does not check any of `window-fixed-size-p',
+`window-min-height' or `window-min-width'.  All these checks have to
+be applied on the Elisp level.  */)
+     (Lisp_Object frame, Lisp_Object horizontal)
+{
+  struct frame *f;
+  struct window *r;
+  int horflag = !NILP (horizontal);
 
-                 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
-                 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
+  if (NILP (frame))
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame);
 
-                 delta -= this_one;
-               }
+  f = XFRAME (frame);
+  r = XWINDOW (FRAME_ROOT_WINDOW (f));
 
-             next = XWINDOW (next)->next;
-           }
+  if (!window_resize_check (r, horflag)
+      || ! EQ (r->new_total, (horflag ? r->total_cols : r->total_lines)))
+    return Qnil;
 
-         if (delta == 0)
-           break;
+  BLOCK_INPUT;
+  window_resize_apply (r, horflag);
 
-         if (! NILP (prev))
-           {
-             int this_one = ((*sizefun) (prev)
-                             - window_min_size (XWINDOW (prev), horiz_flag,
-                                                0, 0, &fixed_p));
-             if (!fixed_p)
-               {
-                 if (this_one > delta)
-                   this_one = delta;
+  windows_or_buffers_changed++;
+  FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
-                 first_affected = prev;
+  adjust_glyphs (f);
+  UNBLOCK_INPUT;
 
-                 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
-                 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
+  run_window_configuration_change_hook (f);
 
-                 delta -= this_one;
-               }
+  return Qt;
+}
 
-             prev = XWINDOW (prev)->prev;
-           }
-       }
 
-      xassert (delta == 0);
+/* 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.
 
-      /* Now recalculate the edge positions of all the windows affected,
-        based on the new sizes.  */
-      first_unaffected = next;
-      prev = first_affected;
-      for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
-          prev = next, next = XWINDOW (next)->next)
-       {
-         XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
-         /* This does not change size of NEXT,
-            but it propagates the new top edge to its children */
-         (*setsizefun) (next, (*sizefun) (next), 0);
-       }
-    }
+   This function can delete all windows but the selected one in order to
+   satisfy the request.  The result will be meaningful if and only if
+   F's windows have meaningful sizes when you call this.  */
+void
+resize_frame_windows (struct frame *f, int size, int horflag)
+{
+  Lisp_Object root = f->root_window;
+  struct window *r = XWINDOW (root);
+  Lisp_Object mini = f->minibuffer_window;
+  struct window *m;
+  /* new_size is the new size of the frame's root window.  */
+  int new_size = (horflag
+                 ? size
+                 : (size
+                    - FRAME_TOP_MARGIN (f)
+                    - ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+                       ? 1 : 0)));
+
+  XSETFASTINT (r->top_line, FRAME_TOP_MARGIN (f));
+  if (NILP (r->vchild) && NILP (r->hchild))
+    /* For a leaf root window just set the size.  */
+    if (horflag)
+      XSETFASTINT (r->total_cols, new_size);
+    else
+      XSETFASTINT (r->total_lines, new_size);
   else
     {
-      register int delta1;
-      register int opht = (*sizefun) (parent);
+      /* old_size is the old size of the frame's root window.  */
+      int old_size = XFASTINT (horflag ? r->total_cols : r->total_lines);
+      Lisp_Object delta;
 
-      if (opht <= XINT (*sizep) + delta)
+      XSETINT (delta, new_size - old_size);
+      /* Try a "normal" resize first.  */
+      resize_root_window (root, delta, horflag ? Qt : Qnil, Qnil);
+      if (window_resize_check (r, horflag) && new_size == XINT (r->new_total))
+       window_resize_apply (r, horflag);
+      else
        {
-         /* If trying to grow this window to or beyond size of the parent,
-            just delete all the sibling windows.  */
-         Lisp_Object start, tem, next;
-
-         start = XWINDOW (parent)->vchild;
-         if (NILP (start))
-           start = XWINDOW (parent)->hchild;
-
-         /* Delete any siblings that come after WINDOW.  */
-         tem = XWINDOW (window)->next;
-         while (! NILP (tem))
-           {
-             next = XWINDOW (tem)->next;
-             delete_window (tem);
-             tem = next;
-           }
-
-         /* Delete any siblings that come after WINDOW.
-            Note that if START is not WINDOW, then WINDOW still
-            has siblings, so WINDOW has not yet replaced its parent.  */
-         tem = start;
-         while (! EQ (tem, window))
+         /* Try with "reasonable" minimum sizes next.  */
+         resize_root_window (root, delta, horflag ? Qt : Qnil, Qt);
+         if (window_resize_check (r, horflag)
+             && new_size == XINT (r->new_total))
+           window_resize_apply (r, horflag);
+         else
            {
-             next = XWINDOW (tem)->next;
-             delete_window (tem);
-             tem = next;
+             /* Finally, try with "safe" minimum sizes.  */
+             resize_root_window (root, delta, horflag ? Qt : Qnil, Qsafe);
+             if (window_resize_check (r, horflag)
+                 && new_size == XINT (r->new_total))
+               window_resize_apply (r, horflag);
+             else
+               {
+                 /* We lost.  Delete all windows but the frame's
+                    selected one.  */
+                 root = f->selected_window;
+                 Fdelete_other_windows_internal (root, Qnil);
+                 if (horflag)
+                   XSETFASTINT (XWINDOW (root)->total_cols, new_size);
+                 else
+                   XSETFASTINT (XWINDOW (root)->total_lines, new_size);
+               }
            }
        }
+    }
+
+  if (FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+    {
+      m = XWINDOW (mini);
+      if (horflag)
+       XSETFASTINT (m->total_cols, size);
       else
        {
-         /* Otherwise, make delta1 just right so that if we add
-            delta1 lines to this window and to the parent, and then
-            shrink the parent back to its original size, the new
-            proportional size of this window will increase by delta.
-
-            The function size_window will compute the new height h'
-            of the window from delta1 as:
-
-            e = delta1/n
-            x = delta1 - delta1/n * n for the 1st resizable child
-            h' = h + e + x
-
-            where n is the number of children that can be resized.
-            We can ignore x by choosing a delta1 that is a multiple of
-            n.  We want the height of this window to come out as
-
-            h' = h + delta
-
-            So, delta1 must be
-
-            h + e = h + delta
-            delta1/n = delta
-            delta1 = n * delta.
-
-            The number of children n equals the number of resizable
-            children of this window + 1 because we know window itself
-            is resizable (otherwise we would have signaled an error).
-
-            This reasoning is not correct when other windows become too
-            small and shrink_windows refuses to delete them.  Below we
-            use resize_proportionally to work around this problem.  */
-
-         struct window *w = XWINDOW (window);
-         Lisp_Object s;
-         int n = 1;
-
-         for (s = w->next; WINDOWP (s); s = XWINDOW (s)->next)
-           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
-             ++n;
-         for (s = w->prev; WINDOWP (s); s = XWINDOW (s)->prev)
-           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
-             ++n;
-
-         delta1 = n * delta;
-
-         /* Add delta1 lines or columns to this window, and to the parent,
-            keeping things consistent while not affecting siblings.  */
-         XSETINT (CURSIZE (parent), opht + delta1);
-         (*setsizefun) (window, XINT (*sizep) + delta1, 0);
-
-         /* Squeeze out delta1 lines or columns from our parent,
-            shrinking this window and siblings proportionately.  This
-            brings parent back to correct size.  Delta1 was calculated
-            so this makes this window the desired size, taking it all
-            out of the siblings.
-
-            Temporarily set resize_proportionally to Qt to assure that,
-            if necessary, shrink_windows deletes smaller windows rather
-            than shrink this window.  */
-         w->resize_proportionally = Qt;
-         (*setsizefun) (parent, opht, 0);
-         w->resize_proportionally = Qnil;
+         /* Are we sure we always want 1 line here?  */
+         XSETFASTINT (m->total_lines, 1);
+         XSETFASTINT (m->top_line, XINT (r->top_line) + XINT (r->total_lines));
        }
     }
-
-  XSETFASTINT (p->last_modified, 0);
-  XSETFASTINT (p->last_overlay_modified, 0);
-
-  /* Adjust glyph matrices. */
-  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
 }
 
 
-/* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
-   HORIZ_FLAG nonzero means adjust the width, moving the right edge.
-   zero means adjust the height, moving the bottom edge.
-
-   Following siblings of the selected window are resized to fulfill
-   the size request.  If they become too small in the process, they
-   are not deleted; instead, we signal an error.  */
-
-static void
-adjust_window_trailing_edge (window, delta, horiz_flag)
-     Lisp_Object window;
-     int delta, horiz_flag;
-{
-  Lisp_Object parent, child;
-  struct window *p;
-  Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
-  int delcount = window_deletion_count;
+DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0,
+       doc: /* Split window OLD.
+Second argument TOTAL-SIZE specifies the number of lines or columns of the
+new window.  In any case TOTAL-SIZE must be a positive integer.
 
-  CHECK_WINDOW (window);
+Third argument SIDE nil (or `below') specifies that the new window shall
+be located below WINDOW.  SIDE `above' means the new window shall be
+located above WINDOW.  In both cases TOTAL-SIZE specifies the number of
+lines of the new window including space reserved for the mode and/or
+header line.
 
-  /* Give up if this window cannot be resized.  */
-  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
-    error ("Window is not resizable");
+SIDE t (or `right') specifies that the new window shall be located on
+the right side of WINDOW.  SIDE `left' means the new window shall be
+located on the left of WINDOW.  In both cases TOTAL-SIZE specifies the
+number of columns of the new window including space reserved for fringes
+and the scrollbar or a divider column.
 
-  while (1)
-    {
-      Lisp_Object first_parallel = Qnil;
+Fourth argument NORMAL-SIZE specifies the normal size of the new window
+according to the SIDE argument.
 
-      if (NILP (window))
-       {
-         /* This happens if WINDOW on the previous iteration was
-            at top level of the window tree.  */
-         Fset_window_configuration (old_config);
-         error ("Specified window edge is fixed");
-       }
+The new total and normal sizes of all involved windows must have been
+set correctly.  See the code of `split-window' for how this is done.  */)
+  (Lisp_Object old, Lisp_Object total_size, Lisp_Object side, Lisp_Object normal_size)
+{
+  /* OLD (*o) is the window we have to split.  (*p) is either OLD's
+     parent window or an internal window we have to install as OLD's new
+     parent.  REFERENCE (*r) must denote a live window, or is set to OLD
+     provided OLD is a leaf window, or to the frame's selected window.
+     NEW (*n) is the new window created with some parameters taken from
+     REFERENCE (*r).  */
+  register Lisp_Object new, frame, reference;
+  register struct window *o, *p, *n, *r;
+  struct frame *f;
+  int horflag
+    /* HORFLAG is 1 when we split side-by-side, 0 otherwise.  */
+    = EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright);
+  int combination_limit = 0;
+
+  CHECK_WINDOW (old);
+  o = XWINDOW (old);
+  frame = WINDOW_FRAME (o);
+  f = XFRAME (frame);
 
-      p = XWINDOW (window);
-      parent = p->parent;
+  CHECK_NUMBER (total_size);
+
+  /* Set combination_limit to 1 if we have to make a new parent window.
+     We do that if either `window-combination-limit' is t, or OLD has no
+     parent, or OLD is ortho-combined.  */
+  combination_limit =
+    !NILP (Vwindow_combination_limit)
+    || NILP (o->parent)
+    || NILP (horflag
+            ? (XWINDOW (o->parent)->hchild)
+            : (XWINDOW (o->parent)->vchild));
+
+  /* We need a live reference window to initialize some parameters.  */
+  if (WINDOW_LIVE_P (old))
+    /* OLD is live, use it as reference window.  */
+    reference = old;
+  else
+    /* Use the frame's selected window as reference window.  */
+    reference = FRAME_SELECTED_WINDOW (f);
+  r = XWINDOW (reference);
 
-      /* See if this level has windows in parallel in the specified
-        direction.  If so, set FIRST_PARALLEL to the first one.  */
-      if (horiz_flag)
-       {
-         if (! NILP (parent) && !NILP (XWINDOW (parent)->vchild))
-           first_parallel = XWINDOW (parent)->vchild;
-         else if (NILP (parent) && !NILP (p->next))
-           {
-             /* Handle the vertical chain of main window and minibuffer
-                which has no parent.  */
-             first_parallel = window;
-             while (! NILP (XWINDOW (first_parallel)->prev))
-               first_parallel = XWINDOW (first_parallel)->prev;
-           }
-       }
+  /* The following bugs are caught by `split-window'.  */
+  if (MINI_WINDOW_P (o))
+    error ("Attempt to split minibuffer window");
+  else if (XINT (total_size) < (horflag ? 2 : 1))
+    error ("Size of new window too small (after split)");
+  else if (!combination_limit && !NILP (Vwindow_combination_resize))
+    /* `window-combination-resize' non-nil means try to resize OLD's siblings
+       proportionally.  */
+    {
+      p = XWINDOW (o->parent);
+      /* Temporarily pretend we split the parent window.  */
+      XSETINT (p->new_total,
+              XINT (horflag ? p->total_cols : p->total_lines)
+              - XINT (total_size));
+      if (!window_resize_check (p, horflag))
+       error ("Window sizes don't fit");
       else
-       {
-         if (! NILP (parent) && !NILP (XWINDOW (parent)->hchild))
-           first_parallel = XWINDOW (parent)->hchild;
-       }
-
-      /* If this level's succession is in the desired dimension,
-        and this window is the last one, and there is no higher level,
-        its trailing edge is fixed.  */
-      if (NILP (XWINDOW (window)->next) && NILP (first_parallel)
-         && NILP (parent))
-       {
-         Fset_window_configuration (old_config);
-         error ("Specified window edge is fixed");
-       }
-
-      /* Don't make this window too small.  */
-      if (XINT (CURSIZE (window)) + delta
-         < window_min_size_2 (XWINDOW (window), horiz_flag, 0))
-       {
-         Fset_window_configuration (old_config);
-         error ("Cannot adjust window size as specified");
-       }
+       /* Undo the temporary pretension.  */
+       p->new_total = horflag ? p->total_cols : p->total_lines;
+    }
+  else
+    {
+      if (!window_resize_check (o, horflag))
+       error ("Resizing old window failed");
+      else if (XINT (total_size) + XINT (o->new_total)
+              != XINT (horflag ? o->total_cols : o->total_lines))
+       error ("Sum of sizes of old and new window don't fit");
+    }
 
-      /* Clear out some redisplay caches.  */
-      XSETFASTINT (p->last_modified, 0);
-      XSETFASTINT (p->last_overlay_modified, 0);
+  /* This is our point of no return. */
+  if (combination_limit)
+    {
+      /* Save the old value of o->normal_cols/lines.  It gets corrupted
+        by make_parent_window and we need it below for assigning it to
+        p->new_normal.  */
+      Lisp_Object new_normal = horflag ? o->normal_cols : o->normal_lines;
 
-      /* Adjust this window's edge.  */
-      XSETINT (CURSIZE (window),
-              XINT (CURSIZE (window)) + delta);
+      make_parent_window (old, horflag);
+      p = XWINDOW (o->parent);
+      /* Store value of `window-combination-limit' in new parent's
+        combination_limit slot.  */
+      p->combination_limit = Vwindow_combination_limit;
+      /* These get applied below.  */
+      p->new_total = horflag ? o->total_cols : o->total_lines;
+      p->new_normal = new_normal;
+    }
+  else
+    p = XWINDOW (o->parent);
 
-      /* If this window has following siblings in the desired dimension,
-        make them smaller, and exit the loop.
+  windows_or_buffers_changed++;
+  FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+  new = make_window ();
+  n = XWINDOW (new);
+  n->frame = frame;
+  n->parent = o->parent;
+  n->vchild = n->hchild = Qnil;
 
-        (If we reach the top of the tree and can never do this,
-        we will fail and report an error, above.)  */
-      if (NILP (first_parallel))
-       {
-         if (!NILP (p->next))
-           {
-              /* This may happen for the minibuffer.  In that case
-                 the window_deletion_count check below does not work.  */
-              if (XINT (CURSIZE (p->next)) - delta <= 0)
-                {
-                  Fset_window_configuration (old_config);
-                  error ("Cannot adjust window size as specified");
-                }
-
-             XSETINT (CURBEG (p->next),
-                      XINT (CURBEG (p->next)) + delta);
-             size_window (p->next, XINT (CURSIZE (p->next)) - delta,
-                          horiz_flag, 0, 1, 0);
-             break;
-           }
-       }
+  if (EQ (side, Qabove) || EQ (side, Qleft))
+    {
+      n->prev = o->prev;
+      if (NILP (n->prev))
+       if (horflag)
+         p->hchild = new;
+       else
+         p->vchild = new;
       else
-       /* Here we have a chain of parallel siblings, in the other dimension.
-          Change the size of the other siblings.  */
-       for (child = first_parallel;
-            ! NILP (child);
-            child = XWINDOW (child)->next)
-         if (! EQ (child, window))
-           size_window (child, XINT (CURSIZE (child)) + delta,
-                        horiz_flag, 0, 0, 1);
-
-      window = parent;
+       XWINDOW (n->prev)->next = new;
+      n->next = old;
+      o->prev = new;
     }
-
-  /* If we made a window so small it got deleted,
-     we failed.  Report failure.  */
-  if (delcount != window_deletion_count)
+  else
     {
-      Fset_window_configuration (old_config);
-      error ("Cannot adjust window size as specified");
+      n->next = o->next;
+      if (!NILP (n->next))
+       XWINDOW (n->next)->prev = new;
+      n->prev = old;
+      o->next = new;
     }
 
-  /* Adjust glyph matrices. */
-  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
-}
+  n->buffer = Qt;
+  n->window_end_valid = Qnil;
+  memset (&n->last_cursor, 0, sizeof n->last_cursor);
 
-#undef CURBEG
-#undef CURSIZE
+  /* Get special geometry settings from reference window.  */
+  n->left_margin_cols = r->left_margin_cols;
+  n->right_margin_cols = r->right_margin_cols;
+  n->left_fringe_width = r->left_fringe_width;
+  n->right_fringe_width = r->right_fringe_width;
+  n->fringes_outside_margins = r->fringes_outside_margins;
+  n->scroll_bar_width = r->scroll_bar_width;
+  n->vertical_scroll_bar_type = r->vertical_scroll_bar_type;
 
-DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
-       Sadjust_window_trailing_edge, 3, 3, 0,
-       doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
-If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
-Otherwise, adjust the height, moving the bottom edge.
+  /* Directly assign orthogonal coordinates and sizes.  */
+  if (horflag)
+    {
+      n->top_line = o->top_line;
+      n->total_lines = o->total_lines;
+    }
+  else
+    {
+      n->left_col = o->left_col;
+      n->total_cols = o->total_cols;
+    }
 
-Following siblings of the selected window are resized to fulfill
-the size request.  If they become too small in the process, they
-are not deleted; instead, we signal an error.  */)
-  (window, delta, horizontal)
-  Lisp_Object window, delta, horizontal;
-{
-  CHECK_NUMBER (delta);
-  if (NILP (window))
-    window = selected_window;
-  adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
+  /* Iso-coordinates and sizes are assigned by window_resize_apply,
+     get them ready here.  */
+  n->new_total = total_size;
+  n->new_normal = normal_size;
 
-  run_window_configuration_change_hook
-    (XFRAME (WINDOW_FRAME (XWINDOW (window))));
+  BLOCK_INPUT;
+  window_resize_apply (p, horflag);
+  adjust_glyphs (f);
+  /* Set buffer of NEW to buffer of reference window.  Don't run
+     any hooks.  */
+  set_window_buffer (new, r->buffer, 0, 1);
+  UNBLOCK_INPUT;
 
-  return Qnil;
+  /* Maybe we should run the scroll functions in Elisp (which already
+     runs the configuration change hook).  */
+  if (! NILP (Vwindow_scroll_functions))
+    run_hook_with_args_2 (Qwindow_scroll_functions, new,
+                         Fmarker_position (n->start));
+  /* Return NEW.  */
+  return new;
 }
 
 
-\f
-/***********************************************************************
-                       Resizing Mini-Windows
- ***********************************************************************/
-
-static void shrink_window_lowest_first P_ ((struct window *, int));
-
-enum save_restore_action
+DEFUN ("delete-window-internal", Fdelete_window_internal, Sdelete_window_internal, 1, 1, 0,
+       doc: /* Remove WINDOW from its frame.
+WINDOW defaults to the selected window.  Return nil.
+Signal an error when WINDOW is the only window on its frame.  */)
+     (register Lisp_Object window)
 {
-    CHECK_ORIG_SIZES,
-    SAVE_ORIG_SIZES,
-    RESTORE_ORIG_SIZES
-};
-
-static int save_restore_orig_size P_ ((struct window *,
-                                       enum save_restore_action));
-
-/* Shrink windows rooted in window W to HEIGHT.  Take the space needed
-   from lowest windows first.  */
+  register Lisp_Object parent, sibling, frame, root;
+  struct window *w, *p, *s, *r;
+  struct frame *f;
+  int horflag;
+  int before_sibling = 0;
 
-static void
-shrink_window_lowest_first (w, height)
-     struct window *w;
-     int height;
-{
-  struct window *c;
-  Lisp_Object child;
-  int old_height;
+  w = decode_any_window (window);
+  XSETWINDOW (window, w);
+  if (NILP (w->buffer) && NILP (w->hchild) && NILP (w->vchild))
+    /* It's a no-op to delete an already deleted window.  */
+    return Qnil;
 
-  xassert (!MINI_WINDOW_P (w));
+  parent = w->parent;
+  if (NILP (parent))
+    /* Never delete a minibuffer or frame root window.  */
+    error ("Attempt to delete minibuffer or sole ordinary window");
+  else if (NILP (w->prev) && NILP (w->next))
+    /* Rather bow out here, this case should be handled on the Elisp
+       level.  */
+    error ("Attempt to delete sole window of parent");
 
-  /* Set redisplay hints.  */
-  XSETFASTINT (w->last_modified, 0);
-  XSETFASTINT (w->last_overlay_modified, 0);
-  windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+  p = XWINDOW (parent);
+  horflag = NILP (p->vchild);
 
-  old_height = XFASTINT (w->total_lines);
-  XSETFASTINT (w->total_lines, height);
+  frame = WINDOW_FRAME (w);
+  f = XFRAME (frame);
 
-  if (!NILP (w->hchild))
-    {
-      for (child = w->hchild; !NILP (child); child = c->next)
-       {
-         c = XWINDOW (child);
-         c->top_line = w->top_line;
-         shrink_window_lowest_first (c, height);
-       }
+  root = FRAME_ROOT_WINDOW (f);
+  r = XWINDOW (root);
+
+  /* Unlink WINDOW from window tree.  */
+  if (NILP (w->prev))
+    /* Get SIBLING below (on the right of) WINDOW.  */
+    {
+      /* before_sibling 1 means WINDOW is the first child of its
+        parent and thus before the sibling.  */
+      before_sibling = 1;
+      sibling = w->next;
+      s = XWINDOW (sibling);
+      s->prev = Qnil;
+      if (horflag)
+       p->hchild = sibling;
+      else
+       p->vchild = sibling;
     }
-  else if (!NILP (w->vchild))
+  else
+    /* Get SIBLING above (on the left of) WINDOW.  */
     {
-      Lisp_Object last_child;
-      int delta = old_height - height;
-      int last_top;
+      sibling = w->prev;
+      s = XWINDOW (sibling);
+      s->next = w->next;
+      if (!NILP (s->next))
+       XWINDOW (s->next)->prev = sibling;
+    }
 
-      last_child = Qnil;
+  if (window_resize_check (r, horflag)
+      && EQ (r->new_total, (horflag ? r->total_cols : r->total_lines)))
+    /* We can delete WINDOW now.  */
+    {
 
-      /* Find the last child.  We are taking space from lowest windows
-        first, so we iterate over children from the last child
-        backwards.  */
-      for (child = w->vchild; WINDOWP (child); child = XWINDOW (child)->next)
-       last_child = child;
+      /* Block input.  */
+      BLOCK_INPUT;
+      window_resize_apply (p, horflag);
 
-      /* Size children down to their safe heights.  */
-      for (child = last_child; delta && !NILP (child); child = c->prev)
+      /* If this window is referred to by the dpyinfo's mouse
+        highlight, invalidate that slot to be safe (Bug#9904).  */
+      if (!FRAME_INITIAL_P (f))
        {
-         int this_one;
+         Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
 
-         c = XWINDOW (child);
-         this_one = XFASTINT (c->total_lines) - window_min_size_1 (c, 0, 1);
+         if (EQ (hlinfo->mouse_face_window, window))
+           hlinfo->mouse_face_window = Qnil;
+       }
+
+      windows_or_buffers_changed++;
+      Vwindow_list = Qnil;
+      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
-         if (this_one > delta)
-           this_one = delta;
+      w->next = Qnil;  /* Don't delete w->next too.  */
+      free_window_matrices (w);
 
-         shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
-         delta -= this_one;
+      if (!NILP (w->vchild))
+       {
+         delete_all_child_windows (w->vchild);
+         w->vchild = Qnil;
        }
-
-      /* Compute new positions.  */
-      last_top = XINT (w->top_line);
-      for (child = w->vchild; !NILP (child); child = c->next)
+      else if (!NILP (w->hchild))
        {
-         c = XWINDOW (child);
-         c->top_line = make_number (last_top);
-         shrink_window_lowest_first (c, XFASTINT (c->total_lines));
-         last_top += XFASTINT (c->total_lines);
+         delete_all_child_windows (w->hchild);
+         w->hchild = Qnil;
+       }
+      else if (!NILP (w->buffer))
+       {
+         unshow_buffer (w);
+         unchain_marker (XMARKER (w->pointm));
+         unchain_marker (XMARKER (w->start));
+         w->buffer = Qnil;
        }
-    }
-}
 
+      if (NILP (s->prev) && NILP (s->next))
+         /* A matrjoshka where SIBLING has become the only child of
+            PARENT.  */
+       {
+         /* Put SIBLING into PARENT's place.  */
+         replace_window (parent, sibling, 0);
+         /* Have SIBLING inherit the following three slot values from
+            PARENT (the combination_limit slot is not inherited).  */
+         s->normal_cols = p->normal_cols;
+         s->normal_lines = p->normal_lines;
+         /* Mark PARENT as deleted.  */
+         p->vchild = p->hchild = Qnil;
+         /* Try to merge SIBLING into its new parent.  */
+         recombine_windows (sibling);
+       }
 
-/* Save, restore, or check positions and sizes in the window tree
-   rooted at W.  ACTION says what to do.
+      adjust_glyphs (f);
 
-   If ACTION is CHECK_ORIG_SIZES, check if orig_top_line and
-   orig_total_lines members are valid for all windows in the window
-   tree.  Value is non-zero if they are valid.
+      if (!WINDOW_LIVE_P (FRAME_SELECTED_WINDOW (f)))
+       /* We deleted the frame's selected window.  */
+       {
+         /* Use the frame's first window as fallback ...  */
+         Lisp_Object new_selected_window = Fframe_first_window (frame);
+         /* ... but preferably use its most recently used window.  */
+         Lisp_Object mru_window;
+
+         /* `get-mru-window' might fail for some reason so play it safe
+         - promote the first window _without recording it_ first.  */
+         if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
+           Fselect_window (new_selected_window, Qt);
+         else
+           FRAME_SELECTED_WINDOW (f) = new_selected_window;
 
-   If ACTION is SAVE_ORIG_SIZES, save members top and height in
-   orig_top_line and orig_total_lines for all windows in the tree.
+         UNBLOCK_INPUT;
 
-   If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
-   stored in orig_top_line and orig_total_lines for all windows.  */
+         /* Now look whether `get-mru-window' gets us something.  */
+         mru_window = call1 (Qget_mru_window, frame);
+         if (WINDOW_LIVE_P (mru_window)
+             && EQ (XWINDOW (mru_window)->frame, frame))
+           new_selected_window = mru_window;
 
-static int
-save_restore_orig_size (w, action)
-     struct window *w;
-     enum save_restore_action action;
-{
-  int success_p = 1;
+         /* If all ended up well, we now promote the mru window.  */
+         if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
+           Fselect_window (new_selected_window, Qnil);
+         else
+           FRAME_SELECTED_WINDOW (f) = new_selected_window;
+       }
+      else
+       UNBLOCK_INPUT;
 
-  while (w)
+      /* Must be run by the caller:
+        run_window_configuration_change_hook (f);  */
+    }
+  else
+    /* We failed: Relink WINDOW into window tree.  */
     {
-      if (!NILP (w->hchild))
+      if (before_sibling)
        {
-         if (!save_restore_orig_size (XWINDOW (w->hchild), action))
-           success_p = 0;
+         s->prev = window;
+         if (horflag)
+           p->hchild = window;
+         else
+           p->vchild = window;
        }
-      else if (!NILP (w->vchild))
+      else
        {
-         if (!save_restore_orig_size (XWINDOW (w->vchild), action))
-           success_p = 0;
+         s->next = window;
+         if (!NILP (w->next))
+           XWINDOW (w->next)->prev = window;
        }
+      error ("Deletion failed");
+    }
 
-      switch (action)
-       {
-       case CHECK_ORIG_SIZES:
-         if (!INTEGERP (w->orig_top_line) || !INTEGERP (w->orig_total_lines))
-           return 0;
-         break;
+  return Qnil;
+}
+\f
+/***********************************************************************
+                       Resizing Mini-Windows
+ ***********************************************************************/
 
-       case SAVE_ORIG_SIZES:
-         w->orig_top_line = w->top_line;
-         w->orig_total_lines = w->total_lines;
-          XSETFASTINT (w->last_modified, 0);
-          XSETFASTINT (w->last_overlay_modified, 0);
-         break;
+/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we
+   can.  */
+void
+grow_mini_window (struct window *w, int delta)
+{
+  struct frame *f = XFRAME (w->frame);
+  struct window *r;
+  Lisp_Object root, value;
 
-       case RESTORE_ORIG_SIZES:
-         xassert (INTEGERP (w->orig_top_line) && INTEGERP (w->orig_total_lines));
-         w->top_line = w->orig_top_line;
-         w->total_lines = w->orig_total_lines;
-         w->orig_total_lines = w->orig_top_line = Qnil;
-          XSETFASTINT (w->last_modified, 0);
-          XSETFASTINT (w->last_overlay_modified, 0);
-         break;
+  xassert (MINI_WINDOW_P (w));
+  xassert (delta >= 0);
 
-       default:
-         abort ();
-       }
+  root = FRAME_ROOT_WINDOW (f);
+  r = XWINDOW (root);
+  value = call2 (Qwindow_resize_root_window_vertically,
+                root, make_number (- delta));
+  if (INTEGERP (value) && window_resize_check (r, 0))
+    {
+      BLOCK_INPUT;
+      window_resize_apply (r, 0);
 
-      w = NILP (w->next) ? NULL : XWINDOW (w->next);
-    }
+      /* Grow the mini-window.  */
+      XSETFASTINT (w->top_line, XFASTINT (r->top_line) + XFASTINT (r->total_lines));
+      XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - XINT (value));
+      XSETFASTINT (w->last_modified, 0);
+      XSETFASTINT (w->last_overlay_modified, 0);
 
-  return success_p;
+      adjust_glyphs (f);
+      UNBLOCK_INPUT;
+    }
 }
 
 
-/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
-   without deleting other windows.  */
-
+/* Shrink mini-window W.  */
 void
-grow_mini_window (w, delta)
-     struct window *w;
-     int delta;
+shrink_mini_window (struct window *w)
 {
   struct frame *f = XFRAME (w->frame);
-  struct window *root;
+  struct window *r;
+  Lisp_Object root, value;
+  EMACS_INT size;
 
   xassert (MINI_WINDOW_P (w));
-  /* Commenting out the following assertion goes against the stated interface
-     of the function, but it currently does not seem to do anything useful.
-     See discussion of this issue in the thread for bug#4534.
-     xassert (delta >= 0); */
-
-  /* Compute how much we can enlarge the mini-window without deleting
-     other windows.  */
-  root = XWINDOW (FRAME_ROOT_WINDOW (f));
-  if (delta > 0)
-    {
-      int min_height = window_min_size (root, 0, 0, 0, 0);
-      if (XFASTINT (root->total_lines) - delta < min_height)
-       /* Note that the root window may already be smaller than
-          min_height.  */
-       delta = max (0, XFASTINT (root->total_lines) - min_height);
-    }
 
-  if (delta)
+  size = XINT (w->total_lines);
+  if (size > 1)
     {
-      /* Save original window sizes and positions, if not already done.  */
-      if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
-       save_restore_orig_size (root, SAVE_ORIG_SIZES);
+      root = FRAME_ROOT_WINDOW (f);
+      r = XWINDOW (root);
+      value = call2 (Qwindow_resize_root_window_vertically,
+                    root, make_number (size - 1));
+      if (INTEGERP (value) && window_resize_check (r, 0))
+       {
+         BLOCK_INPUT;
+         window_resize_apply (r, 0);
 
-      /* Shrink other windows.  */
-      shrink_window_lowest_first (root, XFASTINT (root->total_lines) - delta);
+         /* Shrink the mini-window.  */
+         XSETFASTINT (w->top_line, XFASTINT (r->top_line) + XFASTINT (r->total_lines));
+         XSETFASTINT (w->total_lines, 1);
 
-      /* Grow the mini-window.  */
-      w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT (root->total_lines));
-      w->total_lines = make_number (XFASTINT (w->total_lines) + delta);
-      XSETFASTINT (w->last_modified, 0);
-      XSETFASTINT (w->last_overlay_modified, 0);
+         XSETFASTINT (w->last_modified, 0);
+         XSETFASTINT (w->last_overlay_modified, 0);
 
-      adjust_glyphs (f);
+         adjust_glyphs (f);
+         UNBLOCK_INPUT;
+       }
+      /* If the above failed for whatever strange reason we must make a
+        one window frame here.  The same routine will be needed when
+        shrinking the frame (and probably when making the initial
+        *scratch* window).  For the moment leave things as they are.  */
     }
 }
 
+DEFUN ("resize-mini-window-internal", Fresize_mini_window_internal, Sresize_mini_window_internal, 1, 1, 0,
+       doc: /* Resize minibuffer window WINDOW.  */)
+     (Lisp_Object window)
+{
+  struct window *w = XWINDOW (window);
+  struct window *r;
+  struct frame *f;
+  int height;
 
-/* Shrink mini-window W.  If there is recorded info about window sizes
-   before a call to grow_mini_window, restore recorded window sizes.
-   Otherwise, if the mini-window is higher than 1 line, resize it to 1
-   line.  */
+  CHECK_WINDOW (window);
+  f = XFRAME (w->frame);
 
-void
-shrink_mini_window (w)
-     struct window *w;
-{
-  struct frame *f = XFRAME (w->frame);
-  struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
+  if (!EQ (FRAME_MINIBUF_WINDOW (XFRAME (w->frame)), window))
+    error ("Not a valid minibuffer window");
+  else if (FRAME_MINIBUF_ONLY_P (f))
+    error ("Cannot resize a minibuffer-only frame");
 
-  if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
+  r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  height = XINT (r->total_lines) + XINT (w->total_lines);
+  if (window_resize_check (r, 0)
+      && XINT (w->new_total) > 0
+      && height == XINT (r->new_total) + XINT (w->new_total))
     {
-      save_restore_orig_size (root, RESTORE_ORIG_SIZES);
-      adjust_glyphs (f);
+      BLOCK_INPUT;
+      window_resize_apply (r, 0);
+
+      w->total_lines = w->new_total;
+      XSETFASTINT (w->top_line, XINT (r->top_line) + XINT (r->total_lines));
+
+      windows_or_buffers_changed++;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
-      windows_or_buffers_changed = 1;
-    }
-  else if (XFASTINT (w->total_lines) > 1)
-    {
-      /* Distribute the additional lines of the mini-window
-        among the other windows.  */
-      Lisp_Object window;
-      XSETWINDOW (window, w);
-      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
+      adjust_glyphs (f);
+      UNBLOCK_INPUT;
+
+      run_window_configuration_change_hook (f);
+      return Qt;
     }
+  else error ("Failed to resize minibuffer window");
 }
-
-
 \f
 /* Mark window cursors off for all windows in the window tree rooted
    at W by setting their phys_cursor_on_p flag to zero.  Called from
@@ -4736,8 +4146,7 @@ shrink_mini_window (w)
    the frame are cleared.  */
 
 void
-mark_window_cursors_off (w)
-     struct window *w;
+mark_window_cursors_off (struct window *w)
 {
   while (w)
     {
@@ -4756,8 +4165,7 @@ mark_window_cursors_off (w)
 /* Return number of lines of text (not counting mode lines) in W.  */
 
 int
-window_internal_height (w)
-     struct window *w;
+window_internal_height (struct window *w)
 {
   int ht = XFASTINT (w->total_lines);
 
@@ -4777,38 +4185,6 @@ window_internal_height (w)
 
   return ht;
 }
-
-
-/* Return the number of columns in W.
-   Don't count columns occupied by scroll bars or the vertical bar
-   separating W from the sibling to its right.  */
-
-int
-window_box_text_cols (w)
-     struct window *w;
-{
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-  int width = XINT (w->total_cols);
-
-  if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
-    /* Scroll bars occupy a few columns.  */
-    width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
-  else if (!FRAME_WINDOW_P (f)
-          && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
-    /* The column of `|' characters separating side-by-side windows
-       occupies one column only.  */
-    width -= 1;
-
-  if (FRAME_WINDOW_P (f))
-    /* On window-systems, fringes and display margins cannot be
-       used for normal text.  */
-    width -= (WINDOW_FRINGE_COLS (w)
-             + WINDOW_LEFT_MARGIN_COLS (w)
-             + WINDOW_RIGHT_MARGIN_COLS (w));
-
-  return width;
-}
-
 \f
 /************************************************************************
                           Window Scrolling
@@ -4822,13 +4198,10 @@ window_box_text_cols (w)
    respectively.  */
 
 static void
-window_scroll (window, n, whole, noerror)
-     Lisp_Object window;
-     int n;
-     int whole;
-     int noerror;
+window_scroll (Lisp_Object window, EMACS_INT n, int whole, int noerror)
 {
   immediate_quit = 1;
+  n = clip_to_bounds (INT_MIN, n, INT_MAX);
 
   /* If we must, use the pixel-based version which is much slower than
      the line-based one but can handle varying line heights.  */
@@ -4846,11 +4219,7 @@ window_scroll (window, n, whole, noerror)
    descriptions.  */
 
 static void
-window_scroll_pixel_based (window, n, whole, noerror)
-     Lisp_Object window;
-     int n;
-     int whole;
-     int noerror;
+window_scroll_pixel_based (Lisp_Object window, int n, int whole, int noerror)
 {
   struct it it;
   struct window *w = XWINDOW (window);
@@ -4859,8 +4228,14 @@ window_scroll_pixel_based (window, n, whole, noerror)
   /* True if we fiddled the window vscroll field without really scrolling.  */
   int vscrolled = 0;
   int x, y, rtop, rbot, rowh, vpos;
+  void *itdata = NULL;
 
   SET_TEXT_POS_FROM_MARKER (start, w->start);
+  /* Scrolling a minibuffer window via scroll bar when the echo area
+     shows long text sometimes resets the minibuffer contents behind
+     our backs.  */
+  if (CHARPOS (start) > ZV)
+    SET_TEXT_POS (start, BEGV, BEGV_BYTE);
 
   /* If PT is not visible in WINDOW, move back one half of
      the screen.  Allow PT to be partially visible, otherwise
@@ -4869,6 +4244,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
 
   if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
     {
+      itdata = bidi_shelve_cache ();
       /* Move backward half the height of the window.  Performance note:
         vmotion used here is about 10% faster, but would give wrong
         results for variable height lines.  */
@@ -4889,6 +4265,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
        }
 
       start = it.current.pos;
+      bidi_unshelve_cache (itdata, 0);
     }
   else if (auto_window_vscroll_p)
     {
@@ -4925,7 +4302,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
              /* Maybe modify window start instead of scrolling.  */
              if (rbot > 0 || w->vscroll < 0)
                {
-                 int spos;
+                 ptrdiff_t spos;
 
                  Fset_window_vscroll (window, make_number (0), Qt);
                  /* If there are other text lines above the current row,
@@ -4936,13 +4313,13 @@ window_scroll_pixel_based (window, n, whole, noerror)
                    spos = min (XINT (Fline_end_position (Qnil)) + 1, ZV);
                  set_marker_restricted (w->start, make_number (spos),
                                         w->buffer);
-                 w->start_at_line_beg = Qt;
-                 w->update_mode_line = Qt;
+                 w->start_at_line_beg = 1;
+                 w->update_mode_line = 1;
                  XSETFASTINT (w->last_modified, 0);
                  XSETFASTINT (w->last_overlay_modified, 0);
                  /* Set force_start so that redisplay_window will run the
                     window-scroll-functions.  */
-                 w->force_start = Qt;
+                 w->force_start = 1;
                  return;
                }
            }
@@ -4951,17 +4328,19 @@ window_scroll_pixel_based (window, n, whole, noerror)
       Fset_window_vscroll (window, make_number (0), Qt);
     }
 
+  itdata = bidi_shelve_cache ();
   /* If scroll_preserve_screen_position is non-nil, we try to set
      point in the same window line as it is now, so get that line.  */
   if (!NILP (Vscroll_preserve_screen_position))
     {
       /* We preserve the goal pixel coordinate across consecutive
-        calls to scroll-up or scroll-down.  This avoids the
+        calls to scroll-up, scroll-down and other commands that
+        have the `scroll-command' property.  This avoids the
         possibility of point becoming "stuck" on a tall line when
         scrolling by one line.  */
       if (window_scroll_pixel_based_preserve_y < 0
-         || (!EQ (current_kboard->Vlast_command, Qscroll_up)
-             && !EQ (current_kboard->Vlast_command, Qscroll_down)))
+         || !SYMBOLP (KVAR (current_kboard, Vlast_command))
+         || NILP (Fget (KVAR (current_kboard, Vlast_command), Qscroll_command)))
        {
          start_display (&it, w, start);
          move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
@@ -4978,7 +4357,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
   start_display (&it, w, start);
   if (whole)
     {
-      int start_pos = IT_CHARPOS (it);
+      ptrdiff_t start_pos = IT_CHARPOS (it);
       int dy = WINDOW_FRAME_LINE_HEIGHT (w);
       dy = max ((window_box_height (w)
                 - next_screen_context_lines * dy),
@@ -4994,7 +4373,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
             looking at an image that is taller that the window height.  */
          while (start_pos == IT_CHARPOS (it)
                 && start_pos > BEGV)
-           move_it_by_lines (&it, -1, 1);
+           move_it_by_lines (&it, -1);
        }
       else if (dy > 0)
        {
@@ -5004,11 +4383,11 @@ window_scroll_pixel_based (window, n, whole, noerror)
             looking at an image that is taller that the window height.  */
          while (start_pos == IT_CHARPOS (it)
                 && start_pos < ZV)
-           move_it_by_lines (&it, 1, 1);
+           move_it_by_lines (&it, 1);
        }
     }
   else
-    move_it_by_lines (&it, n, 1);
+    move_it_by_lines (&it, n);
 
   /* We failed if we find ZV is already on the screen (scrolling up,
      means there's nothing past the end), or if we can't start any
@@ -5028,12 +4407,16 @@ window_scroll_pixel_based (window, n, whole, noerror)
                            - it.current_y + it.max_ascent + it.max_descent);
              adjust_glyphs (it.f);
            }
-         else if (noerror)
-           return;
-         else if (n < 0)       /* could happen with empty buffers */
-           xsignal0 (Qbeginning_of_buffer);
          else
-           xsignal0 (Qend_of_buffer);
+           {
+             bidi_unshelve_cache (itdata, 0);
+             if (noerror)
+               return;
+             else if (n < 0)   /* could happen with empty buffers */
+               xsignal0 (Qbeginning_of_buffer);
+             else
+               xsignal0 (Qend_of_buffer);
+           }
        }
       else
        {
@@ -5041,10 +4424,14 @@ window_scroll_pixel_based (window, n, whole, noerror)
            /* The first line was only partially visible, make it fully
               visible. */
            w->vscroll = 0;
-         else if (noerror)
-           return;
          else
-           xsignal0 (Qbeginning_of_buffer);
+           {
+             bidi_unshelve_cache (itdata, 0);
+             if (noerror)
+               return;
+             else
+               xsignal0 (Qbeginning_of_buffer);
+           }
        }
 
       /* If control gets here, then we vscrolled.  */
@@ -5057,8 +4444,8 @@ window_scroll_pixel_based (window, n, whole, noerror)
 
   if (! vscrolled)
     {
-      int pos = IT_CHARPOS (it);
-      int bytepos;
+      ptrdiff_t pos = IT_CHARPOS (it);
+      ptrdiff_t bytepos;
 
       /* If in the middle of a multi-glyph character move forward to
         the next character.  */
@@ -5072,14 +4459,13 @@ window_scroll_pixel_based (window, n, whole, noerror)
       set_marker_restricted (w->start, make_number (pos),
                             w->buffer);
       bytepos = XMARKER (w->start)->bytepos;
-      w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
-                             ? Qt : Qnil);
-      w->update_mode_line = Qt;
+      w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n');
+      w->update_mode_line = 1;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
       /* Set force_start so that redisplay_window will run the
         window-scroll-functions.  */
-      w->force_start = Qt;
+      w->force_start = 1;
     }
 
   /* The rest of this function uses current_y in a nonstandard way,
@@ -5119,7 +4505,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
          while (it.current_y < this_scroll_margin)
            {
              int prev = it.current_y;
-             move_it_by_lines (&it, 1, 1);
+             move_it_by_lines (&it, 1);
              if (prev == it.current_y)
                break;
            }
@@ -5128,7 +4514,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
     }
   else if (n < 0)
     {
-      int charpos, bytepos;
+      ptrdiff_t charpos, bytepos;
       int partial_p;
 
       /* Save our position, for the
@@ -5153,7 +4539,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
        partial_p = it.current_y + it.ascent + it.descent > it.last_visible_y;
       else
        {
-         move_it_by_lines (&it, 1, 1);
+         move_it_by_lines (&it, 1);
          partial_p = it.current_y > it.last_visible_y;
        }
 
@@ -5180,7 +4566,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
            /* The last line was only partially visible, so back up two
               lines to make sure we're on a fully visible line.  */
            {
-             move_it_by_lines (&it, -2, 0);
+             move_it_by_lines (&it, -2);
              SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
            }
          else
@@ -5188,6 +4574,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
            SET_PT_BOTH (charpos, bytepos);
        }
     }
+  bidi_unshelve_cache (itdata, 0);
 }
 
 
@@ -5195,20 +4582,21 @@ window_scroll_pixel_based (window, n, whole, noerror)
    See the comment of window_scroll for parameter descriptions.  */
 
 static void
-window_scroll_line_based (window, n, whole, noerror)
-     Lisp_Object window;
-     int n;
-     int whole;
-     int noerror;
+window_scroll_line_based (Lisp_Object window, int n, int whole, int noerror)
 {
   register struct window *w = XWINDOW (window);
-  register int opoint = PT, opoint_byte = PT_BYTE;
-  register int pos, pos_byte;
+  /* Fvertical_motion enters redisplay, which can trigger
+     fontification, which in turn can modify buffer text (e.g., if the
+     fontification functions replace escape sequences with faces, as
+     in `grep-mode-font-lock-keywords').  So we use a marker to record
+     the old point position, to prevent crashes in SET_PT_BOTH.  */
+  Lisp_Object opoint_marker = Fpoint_marker ();
+  register ptrdiff_t pos, pos_byte;
   register int ht = window_internal_height (w);
   register Lisp_Object tem;
   int lose;
   Lisp_Object bolp;
-  int startpos;
+  ptrdiff_t startpos;
   Lisp_Object original_pos = Qnil;
 
   /* If scrolling screen-fulls, compute the number of lines to
@@ -5221,8 +4609,8 @@ window_scroll_line_based (window, n, whole, noerror)
   if (!NILP (Vscroll_preserve_screen_position))
     {
       if (window_scroll_preserve_vpos <= 0
-         || (!EQ (current_kboard->Vlast_command, Qscroll_up)
-             && !EQ (current_kboard->Vlast_command, Qscroll_down)))
+         || !SYMBOLP (KVAR (current_kboard, Vlast_command))
+         || NILP (Fget (KVAR (current_kboard, Vlast_command), Qscroll_command)))
        {
          struct position posit
            = *compute_motion (startpos, 0, 0, 0,
@@ -5252,7 +4640,8 @@ window_scroll_line_based (window, n, whole, noerror)
   pos = PT;
   pos_byte = PT_BYTE;
   bolp = Fbolp ();
-  SET_PT_BOTH (opoint, opoint_byte);
+  SET_PT_BOTH (marker_position (opoint_marker),
+              marker_byte_position (opoint_marker));
 
   if (lose)
     {
@@ -5264,23 +4653,18 @@ window_scroll_line_based (window, n, whole, noerror)
 
   if (pos < ZV)
     {
-      int this_scroll_margin = scroll_margin;
-
       /* Don't use a scroll margin that is negative or too large.  */
-      if (this_scroll_margin < 0)
-       this_scroll_margin = 0;
-
-      if (XINT (w->total_lines) < 4 * scroll_margin)
-       this_scroll_margin = XINT (w->total_lines) / 4;
+      int this_scroll_margin =
+       max (0, min (scroll_margin, XINT (w->total_lines) / 4));
 
       set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
-      w->start_at_line_beg = bolp;
-      w->update_mode_line = Qt;
+      w->start_at_line_beg = !NILP (bolp);
+      w->update_mode_line = 1;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
       /* Set force_start so that redisplay_window will run
         the window-scroll-functions.  */
-      w->force_start = Qt;
+      w->force_start = 1;
 
       if (!NILP (Vscroll_preserve_screen_position)
          && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
@@ -5303,8 +4687,9 @@ window_scroll_line_based (window, n, whole, noerror)
          else
            top_margin = pos;
 
-         if (top_margin <= opoint)
-           SET_PT_BOTH (opoint, opoint_byte);
+         if (top_margin <= marker_position (opoint_marker))
+           SET_PT_BOTH (marker_position (opoint_marker),
+                        marker_byte_position (opoint_marker));
          else if (!NILP (Vscroll_preserve_screen_position))
            {
              SET_PT_BOTH (pos, pos_byte);
@@ -5326,8 +4711,9 @@ window_scroll_line_based (window, n, whole, noerror)
          else
            bottom_margin = PT + 1;
 
-         if (bottom_margin > opoint)
-           SET_PT_BOTH (opoint, opoint_byte);
+         if (bottom_margin > marker_position (opoint_marker))
+           SET_PT_BOTH (marker_position (opoint_marker),
+                        marker_byte_position (opoint_marker));
          else
            {
              if (!NILP (Vscroll_preserve_screen_position))
@@ -5357,11 +4743,9 @@ window_scroll_line_based (window, n, whole, noerror)
    up.  This is the guts of Fscroll_up and Fscroll_down.  */
 
 static void
-scroll_command (n, direction)
-     Lisp_Object n;
-     int direction;
+scroll_command (Lisp_Object n, int direction)
 {
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
 
   xassert (eabs (direction) == 1);
 
@@ -5396,8 +4780,7 @@ A near full screen is `next-screen-context-lines' less than a full screen.
 Negative ARG means scroll downward.
 If ARG is the atom `-', scroll downward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'.  */)
-     (arg)
-     Lisp_Object arg;
+  (Lisp_Object arg)
 {
   scroll_command (arg, 1);
   return Qnil;
@@ -5410,8 +4793,7 @@ A near full screen is `next-screen-context-lines' less than a full screen.
 Negative ARG means scroll upward.
 If ARG is the atom `-', scroll upward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'.  */)
-     (arg)
-     Lisp_Object arg;
+  (Lisp_Object arg)
 {
   scroll_command (arg, -1);
   return Qnil;
@@ -5424,7 +4806,7 @@ showing that buffer is used.
 If in the minibuffer, `minibuffer-scroll-window' if non-nil
 specifies the window.  This takes precedence over
 `other-window-scroll-buffer'.  */)
-     ()
+  (void)
 {
   Lisp_Object window;
 
@@ -5474,12 +4856,11 @@ showing that buffer, popping the buffer up if necessary.
 If in the minibuffer, `minibuffer-scroll-window' if non-nil
 specifies the window to scroll.  This takes precedence over
 `other-window-scroll-buffer'.  */)
-     (arg)
-     Lisp_Object arg;
+  (Lisp_Object arg)
 {
   Lisp_Object window;
   struct window *w;
-  int count = SPECPDL_INDEX ();
+  ptrdiff_t count = SPECPDL_INDEX ();
 
   window = Fother_window_for_scrolling ();
   w = XWINDOW (window);
@@ -5518,15 +4899,14 @@ If SET-MINIMUM is non-nil, the new scroll amount becomes the
 lower bound for automatic scrolling, i.e. automatic scrolling
 will not scroll a window to a column less than the value returned
 by this function.  This happens in an interactive call.  */)
-     (arg, set_minimum)
-     register Lisp_Object arg, set_minimum;
+  (register Lisp_Object arg, Lisp_Object set_minimum)
 {
   Lisp_Object result;
-  int hscroll;
+  EMACS_INT hscroll;
   struct window *w = XWINDOW (selected_window);
 
   if (NILP (arg))
-    XSETFASTINT (arg, window_box_text_cols (w) - 2);
+    XSETFASTINT (arg, window_body_cols (w) - 2);
   else
     arg = Fprefix_numeric_value (arg);
 
@@ -5548,15 +4928,14 @@ If SET-MINIMUM is non-nil, the new scroll amount becomes the
 lower bound for automatic scrolling, i.e. automatic scrolling
 will not scroll a window to a column less than the value returned
 by this function.  This happens in an interactive call.  */)
-     (arg, set_minimum)
-     register Lisp_Object arg, set_minimum;
+  (register Lisp_Object arg, Lisp_Object set_minimum)
 {
   Lisp_Object result;
-  int hscroll;
+  EMACS_INT hscroll;
   struct window *w = XWINDOW (selected_window);
 
   if (NILP (arg))
-    XSETFASTINT (arg, window_box_text_cols (w) - 2);
+    XSETFASTINT (arg, window_body_cols (w) - 2);
   else
     arg = Fprefix_numeric_value (arg);
 
@@ -5572,7 +4951,7 @@ by this function.  This happens in an interactive call.  */)
 DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
        doc: /* Return the window which was selected when entering the minibuffer.
 Returns nil, if selected window is not a minibuffer window.  */)
-     ()
+  (void)
 {
   if (minibuf_level > 0
       && MINI_WINDOW_P (XWINDOW (selected_window))
@@ -5586,14 +4965,14 @@ Returns nil, if selected window is not a minibuffer window.  */)
    as opposed to its height.  */
 
 static int
-displayed_window_lines (w)
-     struct window *w;
+displayed_window_lines (struct window *w)
 {
   struct it it;
   struct text_pos start;
   int height = window_box_height (w);
   struct buffer *old_buffer;
   int bottom_y;
+  void *itdata = NULL;
 
   if (XBUFFER (w->buffer) != current_buffer)
     {
@@ -5613,9 +4992,11 @@ displayed_window_lines (w)
   else
     SET_TEXT_POS_FROM_MARKER (start, w->start);
 
+  itdata = bidi_shelve_cache ();
   start_display (&it, w, start);
   move_it_vertically (&it, height);
   bottom_y = line_bottom_y (&it);
+  bidi_unshelve_cache (itdata, 0);
 
   /* rms: On a non-window display,
      the value of it.vpos at the bottom of the screen
@@ -5651,19 +5032,18 @@ the selected window; if the variable `recenter-redisplay' is non-nil,
 also erase the entire frame and redraw it (when `auto-resize-tool-bars'
 is set to `grow-only', this resets the tool-bar's height to the minimum
 height needed); if `recenter-redisplay' has the special value `tty',
-then only tty frame are redrawn.
+then only tty frames are redrawn.
 
 Just C-u as prefix means put point in the center of the window
 and redisplay normally--don't erase and redraw the frame.  */)
-     (arg)
-     register Lisp_Object arg;
+  (register Lisp_Object arg)
 {
   struct window *w = XWINDOW (selected_window);
   struct buffer *buf = XBUFFER (w->buffer);
   struct buffer *obuf = current_buffer;
   int center_p = 0;
-  int charpos, bytepos;
-  int iarg;
+  ptrdiff_t charpos, bytepos;
+  EMACS_INT iarg IF_LINT (= 0);
   int this_scroll_margin;
 
   /* If redisplay is suppressed due to an error, try again.  */
@@ -5675,7 +5055,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
          && (!EQ (Vrecenter_redisplay, Qtty)
              || !NILP (Ftty_type (selected_frame))))
        {
-         int i;
+         ptrdiff_t i;
 
          /* Invalidate pixel data calculated for all compositions.  */
          for (i = 0; i < n_compositions; i++)
@@ -5702,9 +5082,8 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
   /* Do this after making BUF current
      in case scroll_margin is buffer-local.  */
-  this_scroll_margin = max (0, scroll_margin);
-  this_scroll_margin = min (this_scroll_margin,
-                           XFASTINT (w->total_lines) / 4);
+  this_scroll_margin =
+    max (0, min (scroll_margin, XFASTINT (w->total_lines) / 4));
 
   /* Handle centering on a graphical frame specially.  Such frames can
      have variable-height lines and centering point on the basis of
@@ -5715,20 +5094,23 @@ and redisplay normally--don't erase and redraw the frame.  */)
        {
          struct it it;
          struct text_pos pt;
+         void *itdata = bidi_shelve_cache ();
 
          SET_TEXT_POS (pt, PT, PT_BYTE);
          start_display (&it, w, pt);
          move_it_vertically_backward (&it, window_box_height (w) / 2);
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
+         bidi_unshelve_cache (itdata, 0);
        }
       else if (iarg < 0)
        {
          struct it it;
          struct text_pos pt;
-         int nlines = -iarg;
+         ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg);
          int extra_line_spacing;
          int h = window_box_height (w);
+         void *itdata = bidi_shelve_cache ();
 
          iarg = - max (-iarg, this_scroll_margin);
 
@@ -5736,14 +5118,14 @@ and redisplay normally--don't erase and redraw the frame.  */)
          start_display (&it, w, pt);
 
          /* Be sure we have the exact height of the full line containing PT.  */
-         move_it_by_lines (&it, 0, 1);
+         move_it_by_lines (&it, 0);
 
          /* The amount of pixels we have to move back is the window
             height minus what's displayed in the line containing PT,
             and the lines below.  */
          it.current_y = 0;
          it.vpos = 0;
-         move_it_by_lines (&it, nlines, 1);
+         move_it_by_lines (&it, nlines);
 
          if (it.vpos == nlines)
            h -= it.current_y;
@@ -5766,7 +5148,10 @@ and redisplay normally--don't erase and redraw the frame.  */)
              h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
            }
          if (h <= 0)
-           return Qnil;
+           {
+             bidi_unshelve_cache (itdata, 0);
+             return Qnil;
+           }
 
          /* Now find the new top line (starting position) of the window.  */
          start_display (&it, w, pt);
@@ -5782,10 +5167,12 @@ and redisplay normally--don't erase and redraw the frame.  */)
          */
          h += extra_line_spacing;
          while (-it.current_y > h)
-           move_it_by_lines (&it, 1, 1);
+           move_it_by_lines (&it, 1);
 
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
+
+         bidi_unshelve_cache (itdata, 0);
        }
       else
        {
@@ -5821,27 +5208,23 @@ and redisplay normally--don't erase and redraw the frame.  */)
   set_marker_both (w->start, w->buffer, charpos, bytepos);
   w->window_end_valid = Qnil;
 
-  w->optional_new_start = Qt;
+  w->optional_new_start = 1;
 
-  if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
-    w->start_at_line_beg = Qt;
-  else
-    w->start_at_line_beg = Qnil;
+  w->start_at_line_beg = (bytepos == BEGV_BYTE ||
+                         FETCH_BYTE (bytepos - 1) == '\n');
 
   set_buffer_internal (obuf);
   return Qnil;
 }
 
-
 DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
        0, 1, 0,
        doc: /* Return the height in lines of the text display area of WINDOW.
-WINDOW defaults to the selected window.
+If WINDOW is omitted or nil, it defaults to the selected window.
 
-The return value does not include the mode line, any header line, nor
-any partial-height lines in the text display area.  */)
-     (window)
-     Lisp_Object window;
+The returned height does not include the mode line, any header line,
+nor any partial-height lines at the bottom of the text area.  */)
+  (Lisp_Object window)
 {
   struct window *w = decode_window (window);
   int pixel_height = window_box_height (w);
@@ -5854,11 +5237,10 @@ any partial-height lines in the text display area.  */)
 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
        1, 1, "P",
        doc: /* Position point relative to window.
-With no argument, position point at center of window.
-An argument specifies vertical position within the window;
+ARG nil means position point at center of window.
+Else, ARG specifies vertical position within the window;
 zero means top of window, negative means relative to bottom of window.  */)
-     (arg)
-     Lisp_Object arg;
+  (Lisp_Object arg)
 {
   struct window *w = XWINDOW (selected_window);
   int lines, start;
@@ -5880,8 +5262,8 @@ zero means top of window, negative means relative to bottom of window.  */)
       int height = window_internal_height (w);
       Fvertical_motion (make_number (- (height / 2)), window);
       set_marker_both (w->start, w->buffer, PT, PT_BYTE);
-      w->start_at_line_beg = Fbolp ();
-      w->force_start = Qt;
+      w->start_at_line_beg = !NILP (Fbolp ());
+      w->force_start = 1;
     }
   else
     Fgoto_char (w->start);
@@ -5889,15 +5271,14 @@ zero means top of window, negative means relative to bottom of window.  */)
   lines = displayed_window_lines (w);
 
 #if 0
-  this_scroll_margin = max (0, scroll_margin);
-  this_scroll_margin = min (this_scroll_margin, lines / 4);
+  this_scroll_margin = max (0, min (scroll_margin, lines / 4));
 #endif
 
   if (NILP (arg))
     XSETFASTINT (arg, lines / 2);
   else
     {
-      int iarg = XINT (Fprefix_numeric_value (arg));
+      EMACS_INT iarg = XINT (Fprefix_numeric_value (arg));
 
       if (iarg < 0)
        iarg = iarg + lines;
@@ -5954,18 +5335,18 @@ struct save_window_data
 struct saved_window
 {
   struct vectorlike_header header;
-  Lisp_Object window;
-  Lisp_Object buffer, start, pointm, mark;
+
+  Lisp_Object window, buffer, start, pointm, mark;
   Lisp_Object left_col, top_line, total_cols, total_lines;
+  Lisp_Object normal_cols, normal_lines;
   Lisp_Object hscroll, min_hscroll;
   Lisp_Object parent, prev;
   Lisp_Object start_at_line_beg;
   Lisp_Object display_table;
-  Lisp_Object orig_top_line, orig_total_lines;
   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;
-  Lisp_Object dedicated, resize_proportionally;
+  Lisp_Object scroll_bar_width, vertical_scroll_bar_type, dedicated;
+  Lisp_Object combination_limit, window_parameters;
 };
 
 #define SAVED_WINDOW_N(swv,n) \
@@ -5973,16 +5354,14 @@ struct saved_window
 
 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
        doc: /* Return t if OBJECT is a window-configuration object.  */)
-     (object)
-     Lisp_Object object;
+  (Lisp_Object object)
 {
   return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
 }
 
 DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
        doc: /* Return the frame that CONFIG, a window-configuration object, is about.  */)
-     (config)
-     Lisp_Object config;
+  (Lisp_Object config)
 {
   register struct save_window_data *data;
   struct Lisp_Vector *saved_windows;
@@ -6002,15 +5381,15 @@ by `current-window-configuration' (which see).
 If CONFIGURATION was made from a frame that is now deleted,
 only frame-independent values can be restored.  In this case,
 the return value is nil.  Otherwise the value is t.  */)
-     (configuration)
-     Lisp_Object configuration;
+  (Lisp_Object configuration)
 {
   register struct save_window_data *data;
   struct Lisp_Vector *saved_windows;
   Lisp_Object new_current_buffer;
   Lisp_Object frame;
+  Lisp_Object auto_buffer_name;
   FRAME_PTR f;
-  int old_point = -1;
+  ptrdiff_t old_point = -1;
 
   CHECK_WINDOW_CONFIGURATION (configuration);
 
@@ -6018,7 +5397,7 @@ the return value is nil.  Otherwise the value is t.  */)
   saved_windows = XVECTOR (data->saved_windows);
 
   new_current_buffer = data->current_buffer;
-  if (NILP (XBUFFER (new_current_buffer)->name))
+  if (NILP (BVAR (XBUFFER (new_current_buffer), name)))
     new_current_buffer = Qnil;
   else
     {
@@ -6064,12 +5443,16 @@ the return value is nil.  Otherwise the value is t.  */)
      However, there is other stuff we should still try to do below.  */
   if (FRAME_LIVE_P (f))
     {
+      Lisp_Object window;
+      Lisp_Object dead_windows = Qnil;
+      register Lisp_Object tem, par, pers;
       register struct window *w;
       register struct saved_window *p;
       struct window *root_window;
       struct window **leaf_windows;
       int n_leaf_windows;
-      int k, i, n;
+      ptrdiff_t k;
+      int i, n;
 
       /* If the frame has been resized since this window configuration was
         made, we change the frame to the size specified in the
@@ -6135,12 +5518,13 @@ the return value is nil.  Otherwise the value is t.  */)
         Save their current buffers in their height fields, since we may
         need it later, if a buffer saved in the configuration is now
         dead.  */
-      delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
+      delete_all_child_windows (FRAME_ROOT_WINDOW (f));
 
       for (k = 0; k < saved_windows->header.size; k++)
        {
          p = SAVED_WINDOW_N (saved_windows, k);
-         w = XWINDOW (p->window);
+         window = p->window;
+         w = XWINDOW (window);
          w->next = Qnil;
 
          if (!NILP (p->parent))
@@ -6181,11 +5565,11 @@ the return value is nil.  Otherwise the value is t.  */)
          w->top_line = p->top_line;
          w->total_cols = p->total_cols;
          w->total_lines = p->total_lines;
+         w->normal_cols = p->normal_cols;
+         w->normal_lines = p->normal_lines;
          w->hscroll = p->hscroll;
          w->min_hscroll = p->min_hscroll;
          w->display_table = p->display_table;
-         w->orig_top_line = p->orig_top_line;
-         w->orig_total_lines = p->orig_total_lines;
          w->left_margin_cols = p->left_margin_cols;
          w->right_margin_cols = p->right_margin_cols;
          w->left_fringe_width = p->left_fringe_width;
@@ -6194,61 +5578,98 @@ the return value is nil.  Otherwise the value is t.  */)
          w->scroll_bar_width = p->scroll_bar_width;
          w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
          w->dedicated = p->dedicated;
-         w->resize_proportionally = p->resize_proportionally;
+         w->combination_limit = p->combination_limit;
+         /* Restore any window parameters that have been saved.
+            Parameters that have not been saved are left alone.  */
+         for (tem = p->window_parameters; CONSP (tem); tem = XCDR (tem))
+           {
+             pers = XCAR (tem);
+             if (CONSP (pers))
+               {
+                 if (NILP (XCDR (pers)))
+                   {
+                     par = Fassq (XCAR (pers), w->window_parameters);
+                     if (CONSP (par) && !NILP (XCDR (par)))
+                       /* Reset a parameter to nil if and only if it
+                          has a non-nil association.  Don't make new
+                          associations.  */
+                       Fsetcdr (par, Qnil);
+                   }
+                 else
+                   /* Always restore a non-nil value.  */
+                   Fset_window_parameter (window, XCAR (pers), XCDR (pers));
+               }
+           }
+
          XSETFASTINT (w->last_modified, 0);
          XSETFASTINT (w->last_overlay_modified, 0);
 
          /* Reinstall the saved buffer and pointers into it.  */
          if (NILP (p->buffer))
+           /* An internal window.  */
            w->buffer = p->buffer;
+         else if (!NILP (BVAR (XBUFFER (p->buffer), name)))
+           /* If saved buffer is alive, install it.  */
+           {
+             w->buffer = p->buffer;
+             w->start_at_line_beg = !NILP (p->start_at_line_beg);
+             set_marker_restricted (w->start, p->start, w->buffer);
+             set_marker_restricted (w->pointm, p->pointm, w->buffer);
+             Fset_marker (BVAR (XBUFFER (w->buffer), mark),
+                          p->mark, w->buffer);
+
+             /* 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 (!NILP (w->buffer) && !NILP (BVAR (XBUFFER (w->buffer), name)))
+           /* Keep window's old buffer; make sure the markers are
+              real.  */
+           {
+             /* Set window markers at start of visible range.  */
+             if (XMARKER (w->start)->buffer == 0)
+               set_marker_restricted (w->start, make_number (0),
+                                      w->buffer);
+             if (XMARKER (w->pointm)->buffer == 0)
+               set_marker_restricted_both (w->pointm, w->buffer,
+                                           BUF_PT (XBUFFER (w->buffer)),
+                                           BUF_PT_BYTE (XBUFFER (w->buffer)));
+             w->start_at_line_beg = 1;
+           }
+         else if (STRINGP (auto_buffer_name =
+                           Fwindow_parameter (window, Qauto_buffer_name))
+                  && SCHARS (auto_buffer_name) != 0
+                  && !NILP (w->buffer = Fget_buffer_create (auto_buffer_name)))
+           {
+             set_marker_restricted (w->start, make_number (0), w->buffer);
+             set_marker_restricted (w->pointm, make_number (0), w->buffer);
+             w->start_at_line_beg = 1;
+           }
          else
+           /* Window has no live buffer, get one.  */
            {
-             if (!NILP (XBUFFER (p->buffer)->name))
-               /* If saved buffer is alive, install it.  */
-               {
-                 w->buffer = p->buffer;
-                 w->start_at_line_beg = p->start_at_line_beg;
-                 set_marker_restricted (w->start, p->start, w->buffer);
-                 set_marker_restricted (w->pointm, p->pointm, w->buffer);
-                 Fset_marker (XBUFFER (w->buffer)->mark,
-                              p->mark, w->buffer);
-
-                 /* 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 (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
-               /* Else unless window has a live buffer, get one.  */
-               {
-                 w->buffer = Fcdr (Fcar (Vbuffer_alist));
-                 /* This will set the markers to beginning of visible
-                    range.  */
-                 set_marker_restricted (w->start, make_number (0), w->buffer);
-                 set_marker_restricted (w->pointm, make_number (0),w->buffer);
-                 w->start_at_line_beg = Qt;
-               }
-             else
-               /* Keeping window's old buffer; make sure the markers
-                  are real.  */
-               {
-                 /* Set window markers at start of visible range.  */
-                 if (XMARKER (w->start)->buffer == 0)
-                   set_marker_restricted (w->start, make_number (0),
-                                          w->buffer);
-                 if (XMARKER (w->pointm)->buffer == 0)
-                   set_marker_restricted_both (w->pointm, w->buffer,
-                                               BUF_PT (XBUFFER (w->buffer)),
-                                               BUF_PT_BYTE (XBUFFER (w->buffer)));
-                 w->start_at_line_beg = Qt;
-               }
+             /* 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).  */
+             w->buffer = other_buffer_safely (Fcurrent_buffer ());
+             /* This will set the markers to beginning of visible
+                range.  */
+             set_marker_restricted (w->start, make_number (0), w->buffer);
+             set_marker_restricted (w->pointm, make_number (0), w->buffer);
+             w->start_at_line_beg = 1;
+             if (!NILP (w->dedicated))
+               /* Record this window as dead.  */
+               dead_windows = Fcons (window, dead_windows);
+             /* Make sure window is no more dedicated.  */
+             w->dedicated = Qnil;
            }
        }
 
       FRAME_ROOT_WINDOW (f) = data->root_window;
-
       /* Arrange *not* to restore point in the buffer that was
         current when the window configuration was saved.  */
       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
@@ -6256,12 +5677,12 @@ the return value is nil.  Otherwise the value is t.  */)
                               make_number (old_point),
                               XWINDOW (data->current_window)->buffer);
 
-      /* In the following call to `select-window, prevent "swapping
-        out point" in the old selected window using the buffer that
-        has been restored into it.  We already swapped out that point
-        from that window's old buffer.  */
+      /* In the following call to `select-window', prevent "swapping out
+        point" in the old selected window using the buffer that has
+        been restored into it.  We already swapped out that point from
+        that window's old buffer.  */
       select_window (data->current_window, Qnil, 1);
-      XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
+      BVAR (XBUFFER (XWINDOW (selected_window)->buffer), last_selected_window)
        = selected_window;
 
       if (NILP (data->focus_frame)
@@ -6300,9 +5721,16 @@ the return value is nil.  Otherwise the value is t.  */)
        }
 
       adjust_glyphs (f);
-
       UNBLOCK_INPUT;
 
+      /* Scan dead buffer windows.  */
+      for (; CONSP (dead_windows); dead_windows = XCDR (dead_windows))
+       {
+         window = XCAR (dead_windows);
+         if (WINDOW_LIVE_P (window) && !EQ (window, FRAME_ROOT_WINDOW (f)))
+           delete_deletable_window (window);
+       }
+
       /* Fselect_window will have made f the selected frame, so we
         reselect the proper frame here.  Fhandle_switch_frame will change the
         selected window too, but that doesn't make the call to
@@ -6323,39 +5751,45 @@ the return value is nil.  Otherwise the value is t.  */)
   return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 
-/* Mark all windows now on frame as deleted
-   by setting their buffers to nil.  */
 
+/* Recursively delete all child windows reachable via the next, vchild,
+   and hchild slots of WINDOW.  */
 void
-delete_all_subwindows (w)
-     register struct window *w;
+delete_all_child_windows (Lisp_Object window)
 {
+  register struct window *w;
+
+  w = XWINDOW (window);
+
   if (!NILP (w->next))
-    delete_all_subwindows (XWINDOW (w->next));
-  if (!NILP (w->vchild))
-    delete_all_subwindows (XWINDOW (w->vchild));
-  if (!NILP (w->hchild))
-    delete_all_subwindows (XWINDOW (w->hchild));
+    /* Delete WINDOW's siblings (we traverse postorderly).  */
+    delete_all_child_windows (w->next);
 
   w->total_lines = w->buffer;       /* See Fset_window_configuration for excuse.  */
 
-  if (!NILP (w->buffer))
-    unshow_buffer (w);
-
-  /* We set all three of these fields to nil, to make sure that we can
-     distinguish this dead window from any live window.  Live leaf
-     windows will have buffer set, and combination windows will have
-     vchild or hchild set.  */
-  w->buffer = Qnil;
-  w->vchild = Qnil;
-  w->hchild = Qnil;
+  if (!NILP (w->vchild))
+    {
+      delete_all_child_windows (w->vchild);
+      w->vchild = Qnil;
+    }
+  else if (!NILP (w->hchild))
+    {
+      delete_all_child_windows (w->hchild);
+      w->hchild = Qnil;
+    }
+  else if (!NILP (w->buffer))
+    {
+      unshow_buffer (w);
+      unchain_marker (XMARKER (w->pointm));
+      unchain_marker (XMARKER (w->start));
+      w->buffer = Qnil;
+    }
 
   Vwindow_list = Qnil;
 }
 \f
 static int
-count_windows (window)
-     register struct window *window;
+count_windows (register struct window *window)
 {
   register int count = 1;
   if (!NILP (window->next))
@@ -6370,12 +5804,8 @@ count_windows (window)
 
 /* Fill vector FLAT with leaf windows under W, starting at index I.
    Value is last index + 1.  */
-
 static int
-get_leaf_windows (w, flat, i)
-     struct window *w;
-     struct window **flat;
-     int i;
+get_leaf_windows (struct window *w, struct window **flat, int i)
 {
   while (w)
     {
@@ -6394,22 +5824,37 @@ get_leaf_windows (w, flat, i)
 
 
 /* Return a pointer to the glyph W's physical cursor is on.  Value is
-   null if W's current matrix is invalid, so that no meaningfull glyph
+   null if W's current matrix is invalid, so that no meaningful glyph
    can be returned.  */
-
 struct glyph *
-get_phys_cursor_glyph (w)
-     struct window *w;
+get_phys_cursor_glyph (struct window *w)
 {
   struct glyph_row *row;
   struct glyph *glyph;
+  int hpos = w->phys_cursor.hpos;
 
-  if (w->phys_cursor.vpos >= 0
-      && w->phys_cursor.vpos < w->current_matrix->nrows
-      && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
-         row->enabled_p)
-      && row->used[TEXT_AREA] > w->phys_cursor.hpos)
-    glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
+  if (!(w->phys_cursor.vpos >= 0
+       && w->phys_cursor.vpos < w->current_matrix->nrows))
+    return NULL;
+
+  row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
+  if (!row->enabled_p)
+    return NULL;
+
+  if (XINT (w->hscroll))
+    {
+      /* When the window is hscrolled, cursor hpos can legitimately be
+        out of bounds, but we draw the cursor at the corresponding
+        window margin in that case.  */
+      if (!row->reversed_p && hpos < 0)
+       hpos = 0;
+      if (row->reversed_p && hpos >= row->used[TEXT_AREA])
+       hpos = row->used[TEXT_AREA] - 1;
+    }
+
+  if (row->used[TEXT_AREA] > hpos
+      && 0 <= hpos)
+    glyph = row->glyphs[TEXT_AREA] + hpos;
   else
     glyph = NULL;
 
@@ -6418,14 +5863,11 @@ get_phys_cursor_glyph (w)
 
 
 static int
-save_window_save (window, vector, i)
-     Lisp_Object window;
-     struct Lisp_Vector *vector;
-     int i;
+save_window_save (Lisp_Object window, struct Lisp_Vector *vector, int i)
 {
   register struct saved_window *p;
   register struct window *w;
-  register Lisp_Object tem;
+  register Lisp_Object tem, pers, par;
 
   for (;!NILP (window); window = w->next)
     {
@@ -6439,11 +5881,11 @@ save_window_save (window, vector, i)
       p->top_line = w->top_line;
       p->total_cols = w->total_cols;
       p->total_lines = w->total_lines;
+      p->normal_cols = w->normal_cols;
+      p->normal_lines = w->normal_lines;
       p->hscroll = w->hscroll;
       p->min_hscroll = w->min_hscroll;
       p->display_table = w->display_table;
-      p->orig_top_line = w->orig_top_line;
-      p->orig_total_lines = w->orig_total_lines;
       p->left_margin_cols = w->left_margin_cols;
       p->right_margin_cols = w->right_margin_cols;
       p->left_fringe_width = w->left_fringe_width;
@@ -6452,12 +5894,60 @@ save_window_save (window, vector, i)
       p->scroll_bar_width = w->scroll_bar_width;
       p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
       p->dedicated = w->dedicated;
-      p->resize_proportionally = w->resize_proportionally;
+      p->combination_limit = w->combination_limit;
+      p->window_parameters = Qnil;
+
+      if (!NILP (Vwindow_persistent_parameters))
+       {
+         /* Run cycle detection on Vwindow_persistent_parameters.  */
+         Lisp_Object tortoise, hare;
+
+         hare = tortoise = Vwindow_persistent_parameters;
+         while (CONSP (hare))
+           {
+             hare = XCDR (hare);
+             if (!CONSP (hare))
+               break;
+
+             hare = XCDR (hare);
+             tortoise = XCDR (tortoise);
+
+             if (EQ (hare, tortoise))
+               /* Reset Vwindow_persistent_parameters to Qnil.  */
+               {
+                 Vwindow_persistent_parameters = Qnil;
+                 break;
+               }
+           }
+
+         for (tem = Vwindow_persistent_parameters; CONSP (tem);
+              tem = XCDR (tem))
+           {
+             pers = XCAR (tem);
+             /* Save values for persistent window parameters. */
+             if (CONSP (pers) && !NILP (XCDR (pers)))
+               {
+                 par = Fassq (XCAR (pers), w->window_parameters);
+                 if (NILP (par))
+                   /* If the window has no value for the parameter,
+                      make one.  */
+                   p->window_parameters = Fcons (Fcons (XCAR (pers), Qnil),
+                                                 p->window_parameters);
+                 else
+                   /* If the window has a value for the parameter,
+                      save it.  */
+                   p->window_parameters = Fcons (Fcons (XCAR (par),
+                                                        XCDR (par)),
+                                                 p->window_parameters);
+               }
+           }
+       }
+
       if (!NILP (w->buffer))
        {
-         /* Save w's value of point in the window configuration.
-            If w is the selected window, then get the value of point
-            from the buffer; pointm is garbage in the selected window.  */
+         /* Save w's value of point in the window configuration.  If w
+            is the selected window, then get the value of point from
+            the buffer; pointm is garbage in the selected window.  */
          if (EQ (window, selected_window))
            {
              p->pointm = Fmake_marker ();
@@ -6467,11 +5957,13 @@ save_window_save (window, vector, i)
            }
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
+         XMARKER (p->pointm)->insertion_type
+           = !NILP (Vwindow_point_insertion_type);
 
          p->start = Fcopy_marker (w->start, Qnil);
-         p->start_at_line_beg = w->start_at_line_beg;
+         p->start_at_line_beg = w->start_at_line_beg ? Qt : Qnil;
 
-         tem = XBUFFER (w->buffer)->mark;
+         tem = BVAR (XBUFFER (w->buffer), mark);
          p->mark = Fcopy_marker (tem, Qnil);
        }
       else
@@ -6510,9 +6002,10 @@ and for each displayed buffer, where display starts, and the positions of
 point and mark.  An exception is made for point in the current buffer:
 its value is -not- saved.
 This also records the currently selected frame, and FRAME's focus
-redirection (see `redirect-frame-focus').  */)
-     (frame)
-     Lisp_Object frame;
+redirection (see `redirect-frame-focus').  The variable
+`window-persistent-parameters' specifies which window parameters are
+saved by this function.  */)
+  (Lisp_Object frame)
 {
   register Lisp_Object tem;
   register int n_windows;
@@ -6543,113 +6036,12 @@ redirection (see `redirect-frame-focus').  */)
   tem = Fmake_vector (make_number (n_windows), Qnil);
   data->saved_windows = tem;
   for (i = 0; i < n_windows; i++)
-    XVECTOR (tem)->contents[i]
-      = Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil);
+    ASET (tem, i,
+         Fmake_vector (make_number (VECSIZE (struct saved_window)), Qnil));
   save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
   XSETWINDOW_CONFIGURATION (tem, data);
   return (tem);
 }
-
-DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
-       0, UNEVALLED, 0,
-       doc: /* Execute BODY, preserving window sizes and contents.
-Return the value of the last form in BODY.
-Restore which buffer appears in which window, where display starts,
-and the value of point and mark for each window.
-Also restore the choice of selected window.
-Also restore which buffer is current.
-Does not restore the value of point in current buffer.
-usage: (save-window-excursion BODY...)  */)
-     (args)
-     Lisp_Object args;
-{
-  register Lisp_Object val;
-  register int count = SPECPDL_INDEX ();
-
-  record_unwind_protect (Fset_window_configuration,
-                        Fcurrent_window_configuration (Qnil));
-  val = Fprogn (args);
-  return unbind_to (count, val);
-}
-
-
-\f
-/***********************************************************************
-                           Window Split Tree
- ***********************************************************************/
-
-static Lisp_Object
-window_tree (w)
-     struct window *w;
-{
-  Lisp_Object tail = Qnil;
-  Lisp_Object result = Qnil;
-
-  while (w)
-    {
-      Lisp_Object wn;
-
-      XSETWINDOW (wn, w);
-      if (!NILP (w->hchild))
-       wn = Fcons (Qnil, Fcons (Fwindow_edges (wn),
-                                window_tree (XWINDOW (w->hchild))));
-      else if (!NILP (w->vchild))
-       wn = Fcons (Qt, Fcons (Fwindow_edges (wn),
-                              window_tree (XWINDOW (w->vchild))));
-
-      if (NILP (result))
-       {
-         result = tail = Fcons (wn, Qnil);
-       }
-      else
-       {
-         XSETCDR (tail, Fcons (wn, Qnil));
-         tail = XCDR (tail);
-       }
-
-      w = NILP (w->next) ? 0 : XWINDOW (w->next);
-    }
-
-  return result;
-}
-
-
-
-DEFUN ("window-tree", Fwindow_tree, Swindow_tree,
-       0, 1, 0,
-       doc: /* Return the window tree for frame FRAME.
-
-The return value is a list of the form (ROOT MINI), where ROOT
-represents the window tree of the frame's root window, and MINI
-is the frame's minibuffer window.
-
-If the root window is not split, ROOT is the root window itself.
-Otherwise, ROOT is a list (DIR EDGES W1 W2 ...) where DIR is nil for a
-horizontal split, and t for a vertical split, EDGES gives the combined
-size and position of the subwindows in the split, and the rest of the
-elements are the subwindows in the split.  Each of the subwindows may
-again be a window or a list representing a window split, and so on.
-EDGES is a list \(LEFT TOP RIGHT BOTTOM) as returned by `window-edges'.
-
-If FRAME is nil or omitted, return information on the currently
-selected frame.  */)
-     (frame)
-     Lisp_Object frame;
-{
-  FRAME_PTR f;
-
-  if (NILP (frame))
-    frame = selected_frame;
-
-  CHECK_FRAME (frame);
-  f = XFRAME (frame);
-
-  if (!FRAME_LIVE_P (f))
-    return Qnil;
-
-  return window_tree (XWINDOW (FRAME_ROOT_WINDOW (f)));
-}
-
 \f
 /***********************************************************************
                            Marginal Areas
@@ -6663,8 +6055,7 @@ Second arg LEFT-WIDTH specifies the number of character cells to
 reserve for the left marginal area.  Optional third arg RIGHT-WIDTH
 does the same for the right marginal area.  A nil width parameter
 means no margin.  */)
-     (window, left_width, right_width)
-     Lisp_Object window, left_width, right_width;
+  (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width)
 {
   struct window *w = decode_window (window);
 
@@ -6704,12 +6095,11 @@ means no margin.  */)
 DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
        0, 1, 0,
        doc: /* Get width of marginal areas of window WINDOW.
-If WINDOW is omitted or nil, use the currently selected window.
+If WINDOW is omitted or nil, it defaults to the selected window.
 Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
 If a marginal area does not exist, its width will be returned
 as nil.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   struct window *w = decode_window (window);
   return Fcons (w->left_margin_cols, w->right_margin_cols);
@@ -6734,8 +6124,7 @@ the command `set-fringe-style'.
 If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
 outside of the display margins.  By default, fringes are drawn between
 display marginal areas and the text area.  */)
-     (window, left_width, right_width, outside_margins)
-     Lisp_Object window, left_width, right_width, outside_margins;
+  (Lisp_Object window, Lisp_Object left_width, Lisp_Object right_width, Lisp_Object outside_margins)
 {
   struct window *w = decode_window (window);
 
@@ -6770,10 +6159,9 @@ display marginal areas and the text area.  */)
 DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
        0, 1, 0,
        doc: /* Get width of fringes of window WINDOW.
-If WINDOW is omitted or nil, use the currently selected window.
+If WINDOW is omitted or nil, it defaults to the selected window.
 Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   struct window *w = decode_window (window);
 
@@ -6789,8 +6177,8 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
                            Scroll bars
  ***********************************************************************/
 
-DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, Sset_window_scroll_bars,
-       2, 4, 0,
+DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars,
+       Sset_window_scroll_bars, 2, 4, 0,
        doc: /* Set width and type of scroll bars of window WINDOW.
 If window is nil, set scroll bars of the currently selected window.
 Second parameter WIDTH specifies the pixel width for the scroll bar;
@@ -6800,14 +6188,13 @@ 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.  */)
-     (window, width, vertical_type, horizontal_type)
-     Lisp_Object window, width, vertical_type, horizontal_type;
+  (Lisp_Object window, Lisp_Object width, Lisp_Object vertical_type, Lisp_Object horizontal_type)
 {
   struct window *w = decode_window (window);
 
   if (!NILP (width))
     {
-      CHECK_NATNUM (width);
+      CHECK_RANGED_INTEGER (0, width, INT_MAX);
 
       if (XINT (width) == 0)
        vertical_type = Qnil;
@@ -6841,12 +6228,11 @@ Fourth parameter HORIZONTAL-TYPE is currently unused.  */)
 DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
        0, 1, 0,
        doc: /* Get width and type of scroll bars of window WINDOW.
-If WINDOW is omitted or nil, use the currently selected window.
+If WINDOW is omitted or nil, it defaults to the selected window.
 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.  */)
-     (window)
-     Lisp_Object window;
+  (Lisp_Object window)
 {
   struct window *w = decode_window (window);
   return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
@@ -6865,11 +6251,10 @@ value.  */)
 
 DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
        doc: /* Return the amount by which WINDOW is scrolled vertically.
-Use the selected window if WINDOW is nil or omitted.
+If WINDOW is omitted or nil, it defaults to the selected window.
 Normally, value is a multiple of the canonical character height of WINDOW;
 optional second arg PIXELS-P means value is measured in pixels.  */)
-  (window, pixels_p)
-     Lisp_Object window, pixels_p;
+  (Lisp_Object window, Lisp_Object pixels_p)
 {
   Lisp_Object result;
   struct frame *f;
@@ -6902,8 +6287,7 @@ If PIXELS-P is nil, VSCROLL may have to be rounded so that it
 corresponds to an integral number of pixels.  The return value is the
 result of this rounding.
 If PIXELS-P is non-nil, the return value is VSCROLL.  */)
-  (window, vscroll, pixels_p)
-     Lisp_Object window, vscroll, pixels_p;
+  (Lisp_Object window, Lisp_Object vscroll, Lisp_Object pixels_p)
 {
   struct window *w;
   struct frame *f;
@@ -6946,11 +6330,9 @@ If PIXELS-P is non-nil, the return value is VSCROLL.  */)
    first argument being a pointer to the leaf window, and with
    additional argument USER_DATA.  Stops when FN returns 0.  */
 
-void
-foreach_window (f, fn, user_data)
-     struct frame *f;
-     int (* fn) P_ ((struct window *, void *));
-     void *user_data;
+static void
+foreach_window (struct frame *f, int (*fn) (struct window *, void *),
+               void *user_data)
 {
   /* delete_frame may set FRAME_ROOT_WINDOW (f) to Qnil.  */
   if (WINDOWP (FRAME_ROOT_WINDOW (f)))
@@ -6964,10 +6346,7 @@ foreach_window (f, fn, user_data)
    Stop when FN returns 0.  Value is 0 if stopped by FN.  */
 
 static int
-foreach_window_1 (w, fn, user_data)
-     struct window *w;
-     int (* fn) P_ ((struct window *, void *));
-     void *user_data;
+foreach_window_1 (struct window *w, int (*fn) (struct window *, void *), void *user_data)
 {
   int cont;
 
@@ -6992,9 +6371,7 @@ foreach_window_1 (w, fn, user_data)
    the window start.  */
 
 static int
-freeze_window_start (w, freeze_p)
-     struct window *w;
-     void *freeze_p;
+freeze_window_start (struct window *w, void *freeze_p)
 {
   if (MINI_WINDOW_P (w)
       || (WINDOWP (selected_window) /* Can be nil in corner cases.  */
@@ -7014,9 +6391,7 @@ freeze_window_start (w, freeze_p)
    means freeze the window start.  */
 
 void
-freeze_window_starts (f, freeze_p)
-     struct frame *f;
-     int freeze_p;
+freeze_window_starts (struct frame *f, int freeze_p)
 {
   foreach_window (f, freeze_window_start, (void *) (freeze_p ? f : 0));
 }
@@ -7026,118 +6401,82 @@ freeze_window_starts (f, freeze_p)
                            Initialization
  ***********************************************************************/
 
-/* Return 1 if window configurations C1 and C2
-   describe the same state of affairs.  This is used by Fequal.  */
+/* Return 1 if window configurations CONFIGURATION1 and CONFIGURATION2
+   describe the same state of affairs.  This is used by Fequal.
+
+   ignore_positions non-zero means ignore non-matching scroll positions
+   and the like.
+
+   This ignores a couple of things like the dedication status of
+   window, combination_limit and the like.  This might have to be
+   fixed.  */
 
 int
-compare_window_configurations (c1, c2, ignore_positions)
-     Lisp_Object c1, c2;
-     int ignore_positions;
+compare_window_configurations (Lisp_Object configuration1, Lisp_Object configuration2, int ignore_positions)
 {
   register struct save_window_data *d1, *d2;
-  struct Lisp_Vector *sw1, *sw2;
-  int i;
-
-  CHECK_WINDOW_CONFIGURATION (c1);
-  CHECK_WINDOW_CONFIGURATION (c2);
-
-  d1 = (struct save_window_data *) XVECTOR (c1);
-  d2 = (struct save_window_data *) XVECTOR (c2);
-  sw1 = XVECTOR (d1->saved_windows);
-  sw2 = XVECTOR (d2->saved_windows);
-
-  if (d1->frame_cols != d2->frame_cols)
-    return 0;
-  if (d1->frame_lines != d2->frame_lines)
-    return 0;
-  if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
-    return 0;
-  if (! EQ (d1->selected_frame, d2->selected_frame))
-    return 0;
-  /* Don't compare the current_window field directly.
-     Instead see w1_is_current and w2_is_current, below.  */
-  if (! EQ (d1->current_buffer, d2->current_buffer))
-    return 0;
-  if (! ignore_positions)
-    {
-      if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
-       return 0;
-      if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
-       return 0;
-    }
-  /* Don't compare the root_window field.
-     We don't require the two configurations
-     to use the same window object,
-     and the two root windows must be equivalent
-     if everything else compares equal.  */
-  if (! EQ (d1->focus_frame, d2->focus_frame))
-    return 0;
-
-  /* Verify that the two confis have the same number of windows.  */
-  if (sw1->header.size != sw2->header.size)
+  struct Lisp_Vector *sws1, *sws2;
+  ptrdiff_t i;
+
+  CHECK_WINDOW_CONFIGURATION (configuration1);
+  CHECK_WINDOW_CONFIGURATION (configuration2);
+
+  d1 = (struct save_window_data *) XVECTOR (configuration1);
+  d2 = (struct save_window_data *) XVECTOR (configuration2);
+  sws1 = XVECTOR (d1->saved_windows);
+  sws2 = XVECTOR (d2->saved_windows);
+
+  /* Frame settings must match.  */
+  if (d1->frame_cols != d2->frame_cols
+      || d1->frame_lines != d2->frame_lines
+      || d1->frame_menu_bar_lines != d2->frame_menu_bar_lines
+      || !EQ (d1->selected_frame, d2->selected_frame)
+      || !EQ (d1->current_buffer, d2->current_buffer)
+      || (!ignore_positions
+         && (!EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window)
+             || !EQ (d1->minibuf_selected_window, d2->minibuf_selected_window)))
+      || !EQ (d1->focus_frame, d2->focus_frame)
+      /* Verify that the two configurations have the same number of windows.  */
+      || sws1->header.size != sws2->header.size)
     return 0;
 
-  for (i = 0; i < sw1->header.size; i++)
-    {
-      struct saved_window *p1, *p2;
-      int w1_is_current, w2_is_current;
-
-      p1 = SAVED_WINDOW_N (sw1, i);
-      p2 = SAVED_WINDOW_N (sw2, i);
-
-      /* Verify that the current windows in the two
-        configurations correspond to each other.  */
-      w1_is_current = EQ (d1->current_window, p1->window);
-      w2_is_current = EQ (d2->current_window, p2->window);
-
-      if (w1_is_current != w2_is_current)
-       return 0;
-
-      /* Verify that the corresponding windows do match.  */
-      if (! EQ (p1->buffer, p2->buffer))
-       return 0;
-      if (! EQ (p1->left_col, p2->left_col))
-       return 0;
-      if (! EQ (p1->top_line, p2->top_line))
-       return 0;
-      if (! EQ (p1->total_cols, p2->total_cols))
-       return 0;
-      if (! EQ (p1->total_lines, p2->total_lines))
-       return 0;
-      if (! EQ (p1->display_table, p2->display_table))
-       return 0;
-      if (! EQ (p1->parent, p2->parent))
-       return 0;
-      if (! EQ (p1->prev, p2->prev))
-       return 0;
-      if (! ignore_positions)
-       {
-         if (! EQ (p1->hscroll, p2->hscroll))
-           return 0;
-         if (!EQ (p1->min_hscroll, p2->min_hscroll))
-           return 0;
-         if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
-           return 0;
-         if (NILP (Fequal (p1->start, p2->start)))
-           return 0;
-         if (NILP (Fequal (p1->pointm, p2->pointm)))
-           return 0;
-         if (NILP (Fequal (p1->mark, p2->mark)))
-           return 0;
-       }
-      if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
-       return 0;
-      if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
-       return 0;
-      if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
-       return 0;
-      if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
-       return 0;
-      if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
-       return 0;
-      if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
-       return 0;
-      if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
+  for (i = 0; i < sws1->header.size; i++)
+    {
+      struct saved_window *sw1, *sw2;
+
+      sw1 = SAVED_WINDOW_N (sws1, i);
+      sw2 = SAVED_WINDOW_N (sws2, i);
+
+      if (
+          /* The "current" windows in the two configurations must
+             correspond to each other.  */
+         EQ (d1->current_window, sw1->window)
+         != EQ (d2->current_window, sw2->window)
+         /* Windows' buffers must match.  */
+         || !EQ (sw1->buffer, sw2->buffer)
+         || !EQ (sw1->left_col, sw2->left_col)
+         || !EQ (sw1->top_line, sw2->top_line)
+         || !EQ (sw1->total_cols, sw2->total_cols)
+         || !EQ (sw1->total_lines, sw2->total_lines)
+         || !EQ (sw1->display_table, sw2->display_table)
+         /* The next two disjuncts check the window structure for
+            equality.  */
+         || !EQ (sw1->parent, sw2->parent)
+         || !EQ (sw1->prev, sw2->prev)
+         || (!ignore_positions
+             && (!EQ (sw1->hscroll, sw2->hscroll)
+                 || !EQ (sw1->min_hscroll, sw2->min_hscroll)
+                 || !EQ (sw1->start_at_line_beg, sw2->start_at_line_beg)
+                 || NILP (Fequal (sw1->start, sw2->start))
+                 || NILP (Fequal (sw1->pointm, sw2->pointm))
+                 || NILP (Fequal (sw1->mark, sw2->mark))))
+         || !EQ (sw1->left_margin_cols, sw2->left_margin_cols)
+         || !EQ (sw1->right_margin_cols, sw2->right_margin_cols)
+         || !EQ (sw1->left_fringe_width, sw2->left_fringe_width)
+         || !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))
        return 0;
     }
 
@@ -7149,8 +6488,7 @@ DEFUN ("compare-window-configurations", Fcompare_window_configurations,
        doc: /* Compare two window configurations as regards the structure of windows.
 This function ignores details such as the values of point and mark
 and scrolling positions.  */)
-     (x, y)
-     Lisp_Object x, y;
+  (Lisp_Object x, Lisp_Object y)
 {
   if (compare_window_configurations (x, y, 1))
     return Qt;
@@ -7158,7 +6496,7 @@ and scrolling positions.  */)
 }
 \f
 void
-init_window_once ()
+init_window_once (void)
 {
   struct frame *f = make_initial_frame ();
   XSETFRAME (selected_frame, f);
@@ -7171,42 +6509,39 @@ init_window_once ()
 }
 
 void
-init_window ()
+init_window (void)
 {
   Vwindow_list = Qnil;
 }
 
 void
-syms_of_window ()
-{
-  Qscroll_up = intern_c_string ("scroll-up");
-  staticpro (&Qscroll_up);
-
-  Qscroll_down = intern_c_string ("scroll-down");
-  staticpro (&Qscroll_down);
-
-  Qwindow_size_fixed = intern_c_string ("window-size-fixed");
-  staticpro (&Qwindow_size_fixed);
-  Fset (Qwindow_size_fixed, Qnil);
-
-  staticpro (&Qwindow_configuration_change_hook);
-  Qwindow_configuration_change_hook
-    = intern_c_string ("window-configuration-change-hook");
-
-  Qwindowp = intern_c_string ("windowp");
-  staticpro (&Qwindowp);
-
-  Qwindow_configuration_p = intern_c_string ("window-configuration-p");
-  staticpro (&Qwindow_configuration_p);
-
-  Qwindow_live_p = intern_c_string ("window-live-p");
-  staticpro (&Qwindow_live_p);
-
-  Qdisplay_buffer = intern_c_string ("display-buffer");
-  staticpro (&Qdisplay_buffer);
-
-  Qtemp_buffer_show_hook = intern_c_string ("temp-buffer-show-hook");
-  staticpro (&Qtemp_buffer_show_hook);
+syms_of_window (void)
+{
+  DEFSYM (Qscroll_up, "scroll-up");
+  DEFSYM (Qscroll_down, "scroll-down");
+  DEFSYM (Qscroll_command, "scroll-command");
+
+  Fput (Qscroll_up, Qscroll_command, Qt);
+  Fput (Qscroll_down, Qscroll_command, Qt);
+
+  DEFSYM (Qwindow_configuration_change_hook, "window-configuration-change-hook");
+  DEFSYM (Qwindowp, "windowp");
+  DEFSYM (Qwindow_configuration_p, "window-configuration-p");
+  DEFSYM (Qwindow_live_p, "window-live-p");
+  DEFSYM (Qwindow_deletable_p, "window-deletable-p");
+  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 (Qsafe, "safe");
+  DEFSYM (Qdisplay_buffer, "display-buffer");
+  DEFSYM (Qreplace_buffer_in_windows, "replace-buffer-in-windows");
+  DEFSYM (Qrecord_window_buffer, "record-window-buffer");
+  DEFSYM (Qget_mru_window, "get-mru-window");
+  DEFSYM (Qtemp_buffer_show_hook, "temp-buffer-show-hook");
+  DEFSYM (Qabove, "above");
+  DEFSYM (Qbelow, "below");
+  DEFSYM (Qauto_buffer_name, "auto-buffer-name");
+  DEFSYM (Qclone_of, "clone-of");
 
   staticpro (&Vwindow_list);
 
@@ -7218,7 +6553,7 @@ syms_of_window ()
   window_scroll_preserve_hpos = -1;
   window_scroll_preserve_vpos = -1;
 
-  DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
+  DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
               doc: /* Non-nil means call as function to display a help buffer.
 The function is called with one argument, the buffer to be displayed.
 Used by `with-output-to-temp-buffer'.
@@ -7226,95 +6561,164 @@ If this function is used, then it must do the entire job of showing
 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.  */);
   Vtemp_buffer_show_function = Qnil;
 
-  DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
+  DEFVAR_LISP ("minibuffer-scroll-window", Vminibuf_scroll_window,
               doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll.  */);
   Vminibuf_scroll_window = Qnil;
 
-  DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
+  DEFVAR_BOOL ("mode-line-in-non-selected-windows", mode_line_in_non_selected_windows,
               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;
 
-  DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
+  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.  */);
   Vother_window_scroll_buffer = Qnil;
 
-  DEFVAR_BOOL ("auto-window-vscroll", &auto_window_vscroll_p,
-              doc: /* *Non-nil means to automatically adjust `window-vscroll' to view tall lines.  */);
+  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;
 
-  DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
-             doc: /* *Number of lines of continuity when scrolling by screenfuls.  */);
+  DEFVAR_INT ("next-screen-context-lines", next_screen_context_lines,
+             doc: /* Number of lines of continuity when scrolling by screenfuls.  */);
   next_screen_context_lines = 2;
 
-  DEFVAR_INT ("window-min-height", &window_min_height,
-             doc: /* Allow deleting windows less than this tall.
-The value is measured in line units.  If a window wants a modeline it
-is counted as one line.
-
-Emacs honors settings of this variable when enlarging or shrinking
-windows vertically.  A value less than 1 is invalid.  */);
-  window_min_height = 4;
-
-  DEFVAR_INT ("window-min-width", &window_min_width,
-             doc: /* Allow deleting windows less than this wide.
-The value is measured in characters and includes any fringes or
-the scrollbar.
-
-Emacs honors settings of this variable when enlarging or shrinking
-windows horizontally.  A value less than 2 is invalid.  */);
-  window_min_width = 10;
-
   DEFVAR_LISP ("scroll-preserve-screen-position",
-              &Vscroll_preserve_screen_position,
-              doc: /* *Controls if scroll commands move point to keep its screen position unchanged.
+              Vscroll_preserve_screen_position,
+              doc: /* Controls if scroll commands move point to keep its screen position unchanged.
 A value of nil means point does not keep its screen position except
 at the scroll margin or window boundary respectively.
 A value of t means point keeps its screen position if the scroll
 command moved it vertically out of the window, e.g. when scrolling
 by full screens.
-Any other value means point always keeps its screen position.  */);
+Any other value means point always keeps its screen position.
+Scroll commands should have the `scroll-command' property
+on their symbols to be controlled by this variable.  */);
   Vscroll_preserve_screen_position = Qnil;
 
-  DEFVAR_LISP ("window-point-insertion-type", &Vwindow_point_insertion_type,
+  DEFVAR_LISP ("window-point-insertion-type", Vwindow_point_insertion_type,
               doc: /* Type of marker to use for `window-point'.  */);
   Vwindow_point_insertion_type = Qnil;
 
   DEFVAR_LISP ("window-configuration-change-hook",
-              &Vwindow_configuration_change_hook,
+              Vwindow_configuration_change_hook,
               doc: /* Functions to call when window configuration changes.
 The buffer-local part is run once per window, with the relevant window
 selected; while the global part is run only once for the modified frame,
 with the relevant frame selected.  */);
   Vwindow_configuration_change_hook = Qnil;
 
-  DEFVAR_LISP ("recenter-redisplay", &Vrecenter_redisplay,
-              doc: /* If non-nil, then the `recenter' command with a nil argument
-the entire frame to be redrawn; the special value `tty' causes the
-frame to be redrawn only if it is a tty frame.  */);
+  DEFVAR_LISP ("recenter-redisplay", Vrecenter_redisplay,
+              doc: /* Non-nil means `recenter' redraws entire frame.
+If this option is non-nil, then the `recenter' command with a nil
+argument will redraw the entire frame; the special value `tty' causes
+the frame to be redrawn only if it is a tty frame.  */);
   Vrecenter_redisplay = Qtty;
 
+  DEFVAR_LISP ("window-combination-resize", Vwindow_combination_resize,
+              doc: /* If t, resize window combinations proportionally.
+If this variable is nil, splitting a window gets the entire screen space
+for displaying the new window from the window to split.  Deleting and
+resizing a window preferably resizes one adjacent window only.
+
+If this variable is t, splitting a window tries to get the space
+proportionally from all windows in the same combination.  This also
+allows to split a window that is otherwise too small or of fixed size.
+Resizing and deleting a window proportionally resize all windows in the
+same combination.
+
+Other values are reserved for future use.
+
+This variable takes no effect if `window-combination-limit' is non-nil.  */);
+  Vwindow_combination_resize = Qnil;
+
+  DEFVAR_LISP ("window-combination-limit", Vwindow_combination_limit,
+              doc: /* If t, splitting a window makes a new parent window.
+If this variable is nil, splitting a window will create a new parent
+window only if the window has no parent window or the window shall
+become a combination orthogonal to the one it is part of.
+
+If this variable is t, splitting a window always creates a new parent
+window.  If all splits behave this way, each frame's window tree is a
+binary tree and every window but the frame's root window has exactly one
+sibling.
+
+Other values are reserved for future use.
+
+The value of this variable is also assigned to the combination limit of
+the new parent window.  The combination limit of a window can be
+retrieved via the function `window-combination-limit' and altered by the
+function `set-window-combination-limit'.  */);
+  Vwindow_combination_limit = Qnil;
+
+  DEFVAR_LISP ("window-persistent-parameters", Vwindow_persistent_parameters,
+              doc: /* Alist of persistent window parameters.
+This alist specifies which window parameters shall get saved by
+`current-window-configuration' and `window-state-get' and subsequently
+restored to their previous values by `set-window-configuration' and
+`window-state-put'.
+
+The car of each entry of this alist is the symbol specifying the
+parameter.  The cdr is one of the following:
+
+nil means the parameter is neither saved by `window-state-get' nor by
+`current-window-configuration'.
+
+t means the parameter is saved by `current-window-configuration' and,
+provided its WRITABLE argument is nil, by `window-state-get'.
+
+The symbol `writable' means the parameter is saved unconditionally by
+both `current-window-configuration' and `window-state-get'.  Do not use
+this value for parameters without read syntax (like windows or frames).
+
+Parameters not saved by `current-window-configuration' or
+`window-state-get' are left alone by `set-window-configuration'
+respectively are not installed by `window-state-put'.  */);
+  Vwindow_persistent_parameters = list1 (Fcons (Qclone_of, Qt));
 
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);
   defsubr (&Swindowp);
   defsubr (&Swindow_live_p);
+  defsubr (&Swindow_frame);
+  defsubr (&Sframe_root_window);
+  defsubr (&Sframe_first_window);
+  defsubr (&Sframe_selected_window);
+  defsubr (&Sset_frame_selected_window);
   defsubr (&Spos_visible_in_window_p);
   defsubr (&Swindow_line_height);
   defsubr (&Swindow_buffer);
-  defsubr (&Swindow_height);
-  defsubr (&Swindow_width);
-  defsubr (&Swindow_full_width_p);
+  defsubr (&Swindow_parent);
+  defsubr (&Swindow_top_child);
+  defsubr (&Swindow_left_child);
+  defsubr (&Swindow_next_sibling);
+  defsubr (&Swindow_prev_sibling);
+  defsubr (&Swindow_combination_limit);
+  defsubr (&Sset_window_combination_limit);
+  defsubr (&Swindow_use_time);
+  defsubr (&Swindow_top_line);
+  defsubr (&Swindow_left_column);
+  defsubr (&Swindow_total_height);
+  defsubr (&Swindow_total_width);
+  defsubr (&Swindow_normal_size);
+  defsubr (&Swindow_new_total);
+  defsubr (&Swindow_new_normal);
+  defsubr (&Sset_window_new_total);
+  defsubr (&Sset_window_new_normal);
+  defsubr (&Swindow_resize_apply);
+  defsubr (&Swindow_body_height);
+  defsubr (&Swindow_body_width);
   defsubr (&Swindow_hscroll);
   defsubr (&Sset_window_hscroll);
   defsubr (&Swindow_redisplay_end_trigger);
   defsubr (&Sset_window_redisplay_end_trigger);
   defsubr (&Swindow_edges);
   defsubr (&Swindow_pixel_edges);
+  defsubr (&Swindow_absolute_pixel_edges);
   defsubr (&Swindow_inside_edges);
   defsubr (&Swindow_inside_pixel_edges);
+  defsubr (&Swindow_inside_absolute_pixel_edges);
   defsubr (&Scoordinates_in_window_p);
   defsubr (&Swindow_at);
   defsubr (&Swindow_point);
@@ -7328,21 +6732,16 @@ frame to be redrawn only if it is a tty frame.  */);
   defsubr (&Sset_window_display_table);
   defsubr (&Snext_window);
   defsubr (&Sprevious_window);
-  defsubr (&Sother_window);
-  defsubr (&Sget_lru_window);
-  defsubr (&Sget_largest_window);
   defsubr (&Sget_buffer_window);
-  defsubr (&Sdelete_other_windows);
-  defsubr (&Sdelete_windows_on);
-  defsubr (&Sreplace_buffer_in_windows);
-  defsubr (&Sdelete_window);
+  defsubr (&Sdelete_other_windows_internal);
+  defsubr (&Sdelete_window_internal);
+  defsubr (&Sresize_mini_window_internal);
   defsubr (&Sset_window_buffer);
+  defsubr (&Srun_window_configuration_change_hook);
   defsubr (&Sselect_window);
   defsubr (&Sforce_window_update);
-  defsubr (&Ssplit_window);
-  defsubr (&Senlarge_window);
-  defsubr (&Sshrink_window);
-  defsubr (&Sadjust_window_trailing_edge);
+  defsubr (&Stemp_output_buffer_show);
+  defsubr (&Ssplit_window_internal);
   defsubr (&Sscroll_up);
   defsubr (&Sscroll_down);
   defsubr (&Sscroll_left);
@@ -7357,8 +6756,6 @@ frame to be redrawn only if it is a tty frame.  */);
   defsubr (&Swindow_configuration_frame);
   defsubr (&Sset_window_configuration);
   defsubr (&Scurrent_window_configuration);
-  defsubr (&Ssave_window_excursion);
-  defsubr (&Swindow_tree);
   defsubr (&Sset_window_margins);
   defsubr (&Swindow_margins);
   defsubr (&Sset_window_fringes);
@@ -7369,30 +6766,23 @@ frame to be redrawn only if it is a tty frame.  */);
   defsubr (&Sset_window_vscroll);
   defsubr (&Scompare_window_configurations);
   defsubr (&Swindow_list);
+  defsubr (&Swindow_list_1);
+  defsubr (&Swindow_prev_buffers);
+  defsubr (&Sset_window_prev_buffers);
+  defsubr (&Swindow_next_buffers);
+  defsubr (&Sset_window_next_buffers);
   defsubr (&Swindow_parameters);
   defsubr (&Swindow_parameter);
   defsubr (&Sset_window_parameter);
-
 }
 
 void
-keys_of_window ()
+keys_of_window (void)
 {
-  initial_define_key (control_x_map, '1', "delete-other-windows");
-  initial_define_key (control_x_map, '2', "split-window");
-  initial_define_key (control_x_map, '0', "delete-window");
-  initial_define_key (control_x_map, 'o', "other-window");
-  initial_define_key (control_x_map, '^', "enlarge-window");
   initial_define_key (control_x_map, '<', "scroll-left");
   initial_define_key (control_x_map, '>', "scroll-right");
 
-  initial_define_key (global_map, Ctl ('V'), "scroll-up");
+  initial_define_key (global_map, Ctl ('V'), "scroll-up-command");
   initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
-  initial_define_key (meta_map, 'v', "scroll-down");
-
-  initial_define_key (global_map, Ctl('L'), "recenter");
-  initial_define_key (meta_map, 'r', "move-to-window-line");
+  initial_define_key (meta_map, 'v', "scroll-down-command");
 }
-
-/* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
-   (do not change this comment) */