(Fset_window_hscroll, Fpos_visible_in_window_p):
[bpt/emacs.git] / src / window.c
index 4839830..2b22716 100644 (file)
@@ -1,7 +1,7 @@
 /* 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  Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -17,8 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include <config.h>
 #include "lisp.h"
@@ -50,6 +50,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+Lisp_Object Qscroll_up, Qscroll_down;
 Lisp_Object Qwindow_size_fixed;
 extern Lisp_Object Qleft_margin, Qright_margin;
 
@@ -62,10 +63,10 @@ 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));
 static int window_min_size P_ ((struct window *, int, int, int *));
-static void size_window P_ ((Lisp_Object, 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, 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,
@@ -210,6 +211,14 @@ Lisp_Object Vwindow_configuration_change_hook;
 
 Lisp_Object Vscroll_preserve_screen_position;
 
+/* 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_y;
+
 #if 0 /* This isn't used anywhere.  */
 /* Nonzero means we can split a frame even if it is "unsplittable".  */
 static int inhibit_frame_unsplittable;
@@ -273,7 +282,6 @@ make_window ()
   XSETWINDOW (val, p);
   XSETFASTINT (p->last_point, 0);
   p->frozen_window_start_p = 0;
-  p->height_fixed_p = 0;
   p->last_cursor_off_p = p->cursor_off_p = 0;
   p->left_margin_cols = Qnil;
   p->right_margin_cols = Qnil;
@@ -325,13 +333,16 @@ 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 (X Y PARTIAL) where X and Y are the pixel coordinates
-relative to the top left corner of the window. PARTIAL is nil if the character
-after POS is fully visible; otherwise it is a cons (RTOP . RBOT) where RTOP
-and RBOT are the number of pixels invisible at the top and bottom of the row.  */)
+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;
 {
@@ -340,14 +351,16 @@ and RBOT are the number of pixels invisible at the top and bottom of the row.  *
   register struct buffer *buf;
   struct text_pos top;
   Lisp_Object in_window = Qnil;
-  int rtop, rbot, fully_p = 1;
+  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 (!NILP (pos))
+  if (EQ (pos, Qt))
+    posint = -1;
+  else if (!NILP (pos))
     {
       CHECK_NUMBER_COERCE_MARKER (pos);
       posint = XINT (pos);
@@ -359,24 +372,138 @@ and RBOT are the number of pixels invisible at the top and bottom of the row.  *
 
   /* If position is above window start or outside buffer boundaries,
      or if window start is out of range, position is not visible.  */
-  if (posint >= CHARPOS (top)
-      && posint <= BUF_ZV (buf)
+  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, NILP (partially))
+      && 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))
-    in_window = Fcons (make_number (x),
-                      Fcons (make_number (y),
-                             Fcons ((fully_p ? Qnil
-                                    : Fcons (make_number (rtop),
-                                             make_number (rbot))),
-                                    Qnil)));
+    {
+      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.
+If WINDOW is nil or omitted, use 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' and `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 row, relative to the top
+of the first text line, and OFFBOT is the number of off-window pixels at
+the bottom of the text row.  If there are off-window pixels at the top
+of the (first) text row, 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.  */)
+     (line, window)
+     Lisp_Object line, window;
+{
+  register struct window *w;
+  register struct buffer *b;
+  struct glyph_row *row, *end_row;
+  int max_y, crop, i, 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));
+}
+
+
 \f
 static struct window *
 decode_window (window)
@@ -441,7 +568,7 @@ DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
 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 becomes invisible.  */)
+window so that the location of point moves off-window.  */)
      (window, ncol)
      Lisp_Object window, ncol;
 {
@@ -653,12 +780,24 @@ coordinates_in_window (w, x, y)
          || WINDOW_RIGHTMOST_P (w))
        {
          if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
-           return ON_VERTICAL_BORDER;
+           {
+             /* 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
        {
          if (abs (*x - x1) < grabbable_width)
-           return ON_VERTICAL_BORDER;
+           {
+             /* 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)
@@ -683,7 +822,10 @@ coordinates_in_window (w, x, y)
 
   /* Outside any interesting column?  */
   if (*x < left_x || *x > right_x)
-    return ON_SCROLL_BAR;
+    {
+      *y -= top_y;
+      return ON_SCROLL_BAR;
+    }
 
   lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
   rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
@@ -697,7 +839,13 @@ coordinates_in_window (w, x, y)
          && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
          && !WINDOW_RIGHTMOST_P (w)
          && (abs (*x - right_x) < grabbable_width))
-       return ON_VERTICAL_BORDER;
+       {
+         /* 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
     {
@@ -709,6 +857,8 @@ coordinates_in_window (w, x, y)
        {
          /* 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;
        }
     }
@@ -740,9 +890,9 @@ coordinates_in_window (w, x, y)
              ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
              : (*x >= right_x - rmargin_width)))
        {
-         *x -= right_x;
-         if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
-           *x -= WINDOW_RIGHT_FRINGE_WIDTH (w);
+         *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;
        }
@@ -754,7 +904,7 @@ coordinates_in_window (w, x, y)
     }
 
   /* Everything special ruled out - must be on text area */
-  *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
+  *x -= text_left;
   *y -= top_y;
   return ON_TEXT;
 }
@@ -1015,9 +1165,11 @@ if it isn't already recorded.  */)
   Lisp_Object value;
   struct window *w = decode_window (window);
   Lisp_Object buf;
+  struct buffer *b;
 
   buf = w->buffer;
   CHECK_BUFFER (buf);
+  b = XBUFFER (buf);
 
 #if 0 /* This change broke some things.  We should make it later.  */
   /* If we don't know the end position, return nil.
@@ -1030,11 +1182,20 @@ if it isn't already recorded.  */)
 
   if (! NILP (update)
       && ! (! NILP (w->window_end_valid)
-           && XFASTINT (w->last_modified) >= MODIFF))
+           && XFASTINT (w->last_modified) >= BUF_MODIFF (b))
+      && !noninteractive)
     {
       struct text_pos startp;
       struct it it;
-      struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
+      struct buffer *old_buffer = NULL;
+
+      /* Cannot use Fvertical_motion because that function doesn't
+        cope with variable-height lines.  */
+      if (b != current_buffer)
+       {
+         old_buffer = current_buffer;
+         set_buffer_internal (b);
+       }
 
       /* In case W->start is out of the range, use something
          reasonable.  This situation occurred when loading a file with
@@ -1048,14 +1209,6 @@ if it isn't already recorded.  */)
       else
        SET_TEXT_POS_FROM_MARKER (startp, w->start);
 
-      /* Cannot use Fvertical_motion because that function doesn't
-        cope with variable-height lines.  */
-      if (b != current_buffer)
-       {
-         old_buffer = current_buffer;
-         set_buffer_internal (b);
-       }
-
       start_display (&it, w, startp);
       move_it_vertically (&it, window_box_height (w));
       if (it.current_y < it.last_visible_y)
@@ -1066,7 +1219,7 @@ if it isn't already recorded.  */)
        set_buffer_internal (old_buffer);
     }
   else
-    XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+    XSETINT (value, BUF_Z (b) - XFASTINT (w->window_end_pos));
 
   return value;
 }
@@ -1330,7 +1483,7 @@ delete_window (window)
     CHECK_WINDOW (window);
   p = XWINDOW (window);
 
-  /* It's okay to delete an already-deleted window.  */
+  /* It's a no-op to delete an already-deleted window.  */
   if (NILP (p->buffer)
       && NILP (p->hchild)
       && NILP (p->vchild))
@@ -1394,6 +1547,9 @@ delete_window (window)
       }
   }
 
+  /* 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) */
@@ -1472,7 +1628,7 @@ delete_window (window)
 
   /* 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);
@@ -1819,7 +1975,7 @@ DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
 All windows on current frame are arranged in a cyclic order.
 This command selects the window ARG steps away in that order.
 A negative ARG moves in the opposite order.  The optional second
-argument ALL_FRAMES has the same meaning as in `next-window', which see.  */)
+argument ALL-FRAMES has the same meaning as in `next-window', which see.  */)
      (arg, all_frames)
      Lisp_Object arg, all_frames;
 {
@@ -1851,7 +2007,8 @@ MINIBUF neither nil nor t means never include the minibuffer window.  */)
      Lisp_Object frame, minibuf, window;
 {
   if (NILP (window))
-    window = selected_window;
+    window = FRAMEP (frame) ? XFRAME (frame)->selected_window : selected_window;
+  CHECK_WINDOW (window);
   if (NILP (frame))
     frame = selected_frame;
 
@@ -1959,7 +2116,7 @@ window_loop (type, obj, mini, frames)
   GCPRO1 (windows);
   best_window = Qnil;
 
-  for (; CONSP (windows); windows = CDR (windows))
+  for (; CONSP (windows); windows = XCDR (windows))
     {
       struct window *w;
 
@@ -1993,11 +2150,13 @@ window_loop (type, obj, mini, frames)
            break;
 
          case GET_LRU_WINDOW:
-           /* t as arg means consider only full-width windows */
-           if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (w))
-             break;
-           /* Ignore dedicated windows and minibuffers.  */
-           if (MINI_WINDOW_P (w) || EQ (w->dedicated, Qt))
+           /* `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)
@@ -2048,9 +2207,9 @@ window_loop (type, obj, mini, frames)
            break;
 
          case GET_LARGEST_WINDOW:
-           {
+           { /* nil `obj' means to ignore dedicated windows.  */
              /* Ignore dedicated windows and minibuffers.  */
-             if (MINI_WINDOW_P (w) || EQ (w->dedicated, Qt))
+             if (MINI_WINDOW_P (w) || (NILP (obj) && !NILP (w->dedicated)))
                break;
 
              if (NILP (best_window))
@@ -2144,43 +2303,47 @@ check_all_windows ()
   window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
 }
 
-DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
+DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
        doc: /* Return the window least recently selected or used for display.
 Return a full-width window if possible.
 A minibuffer window is never a candidate.
-A dedicated window is never a candidate, so if all windows are dedicated,
-the value is nil.
+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)
-     Lisp_Object 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, Qt, 0, frame);
+  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, Qnil, 0, frame);
+  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, 1, 0,
+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, so if all windows are dedicated,
-the value is nil.
+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)
-     Lisp_Object frame;
+    (frame, dedicated)
+     Lisp_Object frame, dedicated;
 {
-  return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
+  return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
                      frame);
 }
 
@@ -2438,27 +2601,22 @@ window_fixed_size_p (w, width_p, check_siblings_p)
     }
   else if (BUFFERP (w->buffer))
     {
-      if (w->height_fixed_p && !width_p)
-       fixed_p = 1;
-      else
-       {
-         struct buffer *old = current_buffer;
-         Lisp_Object val;
+      struct buffer *old = current_buffer;
+      Lisp_Object val;
 
-         current_buffer = XBUFFER (w->buffer);
-         val = find_symbol_value (Qwindow_size_fixed);
-         current_buffer = old;
+      current_buffer = XBUFFER (w->buffer);
+      val = find_symbol_value (Qwindow_size_fixed);
+      current_buffer = old;
 
-         fixed_p = 0;
-         if (!EQ (val, Qunbound))
-           {
-             fixed_p = !NILP (val);
+      fixed_p = 0;
+      if (!EQ (val, Qunbound))
+       {
+         fixed_p = !NILP (val);
 
-             if (fixed_p
-                 && ((EQ (val, Qheight) && width_p)
-                     || (EQ (val, Qwidth) && !width_p)))
-               fixed_p = 0;
-           }
+         if (fixed_p
+             && ((EQ (val, Qheight) && width_p)
+                 || (EQ (val, Qwidth) && !width_p)))
+           fixed_p = 0;
        }
 
       /* Can't tell if this one is resizable without looking at
@@ -2557,7 +2715,10 @@ window_min_size_1 (w, width_p)
   else
     {
       if (width_p)
-       size = window_min_width;
+       size = max (window_min_width,
+                   (MIN_SAFE_WINDOW_WIDTH
+                    + WINDOW_FRINGE_COLS (w)
+                    + WINDOW_SCROLL_BAR_COLS (w)));
       else
        {
          if (MINI_WINDOW_P (w)
@@ -2786,17 +2947,23 @@ shrink_windows (total, size, nchildren, shrinkable,
 
 /* 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.  Propagate
-   WINDOW's top or left edge position to children.  Delete windows
-   that become too small unless NODELETE_P is non-zero.
+   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 non-zero.
 
    If NODELETE_P is 2, that means we do delete windows that are
    too small, even if they were too small before!  */
 
 static void
-size_window (window, size, width_p, nodelete_p)
+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;
@@ -2871,6 +3038,7 @@ size_window (window, size, width_p, nodelete_p)
 
   if (!NILP (*sideward))
     {
+      /* We have a chain of parallel siblings whose size should all change.  */
       for (child = *sideward; !NILP (child); child = c->next)
        {
          c = XWINDOW (child);
@@ -2878,8 +3046,44 @@ size_window (window, size, width_p, nodelete_p)
            c->left_col = w->left_col;
          else
            c->top_line = w->top_line;
-         size_window (child, size, width_p, nodelete_p);
+         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;
+
+      for (child = *forward; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         last_child = child;
        }
+
+      child_size = XINT (width_p ? c->total_cols : c->total_lines);
+      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 = XINT (width_p ? c->total_cols : c->total_lines);
+      size_window (child,
+                  size - old_size + child_size,
+                  width_p, nodelete_p, first_only, last_only);
     }
   else if (!NILP (*forward))
     {
@@ -2888,7 +3092,7 @@ size_window (window, size, width_p, nodelete_p)
       int last_pos, first_pos, nchildren, total;
       int *new_sizes = NULL;
 
-      /* Determine the fixed-size portion of the this window, and the
+      /* 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)
@@ -2951,7 +3155,7 @@ size_window (window, size, width_p, nodelete_p)
          /* Set new height.  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);
+         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.  */
@@ -2970,7 +3174,7 @@ size_window (window, size, width_p, nodelete_p)
            int child_size;
            c = XWINDOW (child);
            child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
-           size_window (child, child_size, width_p, 2);
+           size_window (child, child_size, width_p, 2, first_only, last_only);
          }
     }
 }
@@ -2986,7 +3190,7 @@ set_window_height (window, height, nodelete)
      int height;
      int nodelete;
 {
-  size_window (window, height, 0, nodelete);
+  size_window (window, height, 0, nodelete, 0, 0);
 }
 
 
@@ -3001,7 +3205,7 @@ set_window_width (window, width, nodelete)
      int width;
      int nodelete;
 {
-  size_window (window, width, 1, nodelete);
+  size_window (window, width, 1, nodelete, 0, 0);
 }
 
 /* Change window heights in windows rooted in WINDOW by N lines.  */
@@ -3234,7 +3438,7 @@ selects the buffer of the selected window before each command.  */)
         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), Qnil);
+      Fselect_frame (WINDOW_FRAME (w));
     }
   else
     sf->selected_window = window;
@@ -3397,7 +3601,7 @@ displaying BUFFER, then simply raise that frame.
 The variables `special-display-buffer-names',
 `special-display-regexps', `same-window-buffer-names', and
 `same-window-regexps' customize how certain buffer names are handled.
-The latter two take effect only if NOT-THIS-WINDOW is t.
+The latter two take effect only if NOT-THIS-WINDOW is nil.
 
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
@@ -3505,15 +3709,17 @@ displayed.  */)
       if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
        {
          /* Try visible frames first.  */
-         window = Fget_largest_window (Qvisible);
+         window = Fget_largest_window (Qvisible, Qt);
          /* If that didn't work, try iconified frames.  */
          if (NILP (window))
-           window = Fget_largest_window (make_number (0));
+           window = Fget_largest_window (make_number (0), Qt);
+#if 0     /* Don't try windows on other displays.  */
          if (NILP (window))
-           window = Fget_largest_window (Qt);
+           window = Fget_largest_window (Qt, Qt);
+#endif
        }
       else
-       window = Fget_largest_window (frames);
+       window = Fget_largest_window (frames, Qt);
 
       /* If we got a tall enough full-width window that can be split,
         split it.  */
@@ -3526,7 +3732,7 @@ displayed.  */)
        {
          Lisp_Object upper, lower, other;
 
-         window = Fget_lru_window (frames);
+         window = Fget_lru_window (frames, Qt);
          /* If the LRU window is selected, and big enough,
             and can be split, split it.  */
          if (!NILP (window)
@@ -3535,23 +3741,27 @@ displayed.  */)
                  || EQ (XWINDOW (window)->parent, Qnil))
              && window_height (window) >= window_min_height << 1)
            window = Fsplit_window (window, Qnil, Qnil);
+         else
+           window = Fget_lru_window (frames, Qnil);
          /* If Fget_lru_window returned nil, try other approaches.  */
 
          /* Try visible frames first.  */
          if (NILP (window))
            window = Fget_buffer_window (buffer, Qvisible);
          if (NILP (window))
-           window = Fget_largest_window (Qvisible);
+           window = Fget_largest_window (Qvisible, Qnil);
          /* If that didn't work, try iconified frames.  */
          if (NILP (window))
            window = Fget_buffer_window (buffer, make_number (0));
          if (NILP (window))
-           window = Fget_largest_window (make_number (0));
-         /* Try invisible frames.  */
+           window = Fget_largest_window (make_number (0), Qnil);
+
+#if 0     /* Don't try frames on other displays.  */
          if (NILP (window))
            window = Fget_buffer_window (buffer, Qt);
          if (NILP (window))
-           window = Fget_largest_window (Qt);
+           window = Fget_largest_window (Qt, Qnil);
+#endif
          /* As a last resort, make a new frame.  */
          if (NILP (window))
            window = Fframe_selected_window (call0 (Vpop_up_frame_function));
@@ -3573,12 +3783,12 @@ displayed.  */)
                           + XFASTINT (XWINDOW (window)->total_lines));
              enlarge_window (upper,
                              total / 2 - XFASTINT (XWINDOW (upper)->total_lines),
-                             0, 0);
+                             0);
            }
        }
     }
   else
-    window = Fget_lru_window (Qnil);
+    window = Fget_lru_window (Qnil, Qnil);
 
   Fset_window_buffer (window, buffer, Qnil);
   return display_buffer_1 (window);
@@ -3587,7 +3797,7 @@ displayed.  */)
 
 DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
        0, 1, 0,
-       doc: /* Force redisplay of all windows.
+       doc: /* Force all windows to be updated on next redisplay.
 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.  */)
@@ -3650,7 +3860,7 @@ temp_output_buffer_show (buf)
 #endif
   set_buffer_internal (old);
 
-  if (!EQ (Vtemp_buffer_show_function, Qnil))
+  if (!NILP (Vtemp_buffer_show_function))
     call1 (Vtemp_buffer_show_function, buf);
   else
     {
@@ -3732,7 +3942,9 @@ 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.
+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, horflag)
      Lisp_Object window, size, horflag;
@@ -3864,20 +4076,18 @@ See Info node `(elisp)Splitting Windows' for more details and examples.*/)
   return new;
 }
 \f
-DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p",
+DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
        doc: /* Make current window ARG lines bigger.
 From program, optional second arg non-nil means grow sideways ARG columns.
 Interactively, if an argument is not given, make the window one line bigger.
-
-Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
-of the siblings above or to the left of the selected window.  Only
-siblings to the right or below are changed.  */)
-     (arg, side, preserve_before)
-     register Lisp_Object arg, side, preserve_before;
+If HORIZONTAL is non-nil, enlarge horizontally instead of vertically.
+This function can delete windows, even the second window, if they get
+too small.  */)
+     (arg, horizontal)
+     Lisp_Object arg, horizontal;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, XINT (arg), !NILP (side),
-                 !NILP (preserve_before));
+  enlarge_window (selected_window, XINT (arg), !NILP (horizontal));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3885,20 +4095,16 @@ siblings to the right or below are changed.  */)
   return Qnil;
 }
 
-DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "p",
+DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
        doc: /* Make current window ARG lines smaller.
 From program, optional second arg non-nil means shrink sideways arg columns.
-Interactively, if an argument is not given, make the window one line smaller.
-
-Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
-of the siblings above or to the left of the selected window.  Only
+Interactively, if an argument is not given, make the window one line smaller.  Only
 siblings to the right or below are changed.  */)
-     (arg, side, preserve_before)
-     register Lisp_Object arg, side, preserve_before;
+     (arg, side)
+     Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, -XINT (arg), !NILP (side),
-                 !NILP (preserve_before));
+  enlarge_window (selected_window, -XINT (arg), !NILP (side));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3924,40 +4130,40 @@ window_width (window)
 
 
 #define CURBEG(w) \
-  *(widthflag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
+  *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
 
 #define CURSIZE(w) \
-  *(widthflag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
+  *(horiz_flag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
 
 
-/* Enlarge WINDOW by DELTA.  WIDTHFLAG non-zero means
-   increase its width.  Siblings of the selected window are resized to
-   fulfill the size request.  If they become too small in the process,
-   they will be deleted.
+/* Enlarge WINDOW by DELTA.
+   HORIZ_FLAG nonzero means enlarge it horizontally;
+   zero means do it vertically.
 
-   If PRESERVE_BEFORE is nonzero, that means don't alter
-   the siblings to the left or above WINDOW.  */
+   Siblings of the selected window are resized to fulfill the size
+   request.  If they become too small in the process, they will be
+   deleted.  */
 
 static void
-enlarge_window (window, delta, widthflag, preserve_before)
+enlarge_window (window, delta, horiz_flag)
      Lisp_Object window;
-     int delta, widthflag, preserve_before;
+     int delta, horiz_flag;
 {
   Lisp_Object parent, next, prev;
   struct window *p;
   Lisp_Object *sizep;
   int maximum;
   int (*sizefun) P_ ((Lisp_Object))
-    = widthflag ? window_width : window_height;
+    = horiz_flag ? window_width : window_height;
   void (*setsizefun) P_ ((Lisp_Object, int, int))
-    = (widthflag ? set_window_width : set_window_height);
+    = (horiz_flag ? set_window_width : set_window_height);
 
   /* Check values of window_min_width and window_min_height for
      validity.  */
   check_min_window_sizes ();
 
   /* Give up if this window cannot be resized.  */
-  if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
+  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
     error ("Window is not resizable");
 
   /* Find the parent of the selected window.  */
@@ -3968,12 +4174,12 @@ enlarge_window (window, delta, widthflag, preserve_before)
 
       if (NILP (parent))
        {
-         if (widthflag)
+         if (horiz_flag)
            error ("No other window to side of this one");
          break;
        }
 
-      if (widthflag
+      if (horiz_flag
          ? !NILP (XWINDOW (parent)->hchild)
          : !NILP (XWINDOW (parent)->vchild))
        break;
@@ -3988,33 +4194,18 @@ enlarge_window (window, delta, widthflag, preserve_before)
 
     /* Compute the maximum size increment this window can have.  */
 
-    if (preserve_before)
-      {
-       if (!NILP (parent))
-         {
-           maxdelta = (*sizefun) (parent) - XINT (*sizep);
-           /* Subtract size of siblings before, since we can't take that.  */
-           maxdelta -= XINT (CURBEG (window)) - XINT (CURBEG (parent));
-         }
-       else
-         maxdelta = (!NILP (p->next) ? ((*sizefun) (p->next)
-                                        - window_min_size (XWINDOW (p->next),
-                                                           widthflag, 0, 0))
-                     : (delta = 0));
-      }
-    else
-      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),
-                                                         widthflag, 0, 0))
-                 /* This is a minibuffer following a main window.  */
-                 : !NILP (p->prev) ? ((*sizefun) (p->prev)
-                                      - window_min_size (XWINDOW (p->prev),
-                                                         widthflag, 0, 0))
-                 /* This is a frame with only one window, a minibuffer-only
-                    or a minibufferless frame.  */
-                 : (delta = 0));
+    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))
+               /* This is a minibuffer following a main window.  */
+               : !NILP (p->prev) ? ((*sizefun) (p->prev)
+                                    - window_min_size (XWINDOW (p->prev),
+                                                       horiz_flag, 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
@@ -4023,7 +4214,7 @@ enlarge_window (window, delta, widthflag, preserve_before)
       delta = maxdelta;
   }
 
-  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
+  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), horiz_flag, 0, 0))
     {
       delete_window (window);
       return;
@@ -4036,11 +4227,10 @@ enlarge_window (window, delta, widthflag, preserve_before)
   maximum = 0;
   for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
     maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
-                                                   widthflag, 0, 0);
-  if (! preserve_before)
-    for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
-      maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
-                                                     widthflag, 0, 0);
+                                                   horiz_flag, 0, 0);
+  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+                                                   horiz_flag, 0, 0);
 
   /* If we can get it all from them without deleting them, do so.  */
   if (delta <= maximum)
@@ -4056,13 +4246,13 @@ enlarge_window (window, delta, widthflag, preserve_before)
         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) || (!preserve_before && !NILP (prev))))
+            && (!NILP (next) || !NILP (prev)))
        {
          if (! NILP (next))
            {
              int this_one = ((*sizefun) (next)
                              - window_min_size (XWINDOW (next),
-                                                widthflag, 0, &fixed_p));
+                                                horiz_flag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -4080,11 +4270,11 @@ enlarge_window (window, delta, widthflag, preserve_before)
          if (delta == 0)
            break;
 
-         if (!preserve_before && ! NILP (prev))
+         if (! NILP (prev))
            {
              int this_one = ((*sizefun) (prev)
                              - window_min_size (XWINDOW (prev),
-                                                widthflag, 0, &fixed_p));
+                                                horiz_flag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -4180,17 +4370,17 @@ enlarge_window (window, delta, widthflag, preserve_before)
 
             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 signalled an error.  */
+            is resizable (otherwise we would have signalled an error).  */
 
          struct window *w = XWINDOW (window);
          Lisp_Object s;
          int n = 1;
 
          for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
-           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
          for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
-           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
 
          delta1 = n * delta;
@@ -4217,9 +4407,173 @@ enlarge_window (window, delta, widthflag, preserve_before)
   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;
+
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
+  check_min_window_sizes ();
+
+  if (NILP (window))
+    window = Fselected_window ();
+
+  CHECK_WINDOW (window);
+
+  /* Give up if this window cannot be resized.  */
+  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
+    error ("Window is not resizable");
+
+  while (1)
+    {
+      Lisp_Object first_parallel = Qnil;
+
+      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");
+       }
+
+      p = XWINDOW (window);
+      parent = p->parent;
+
+      /* 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;
+           }
+       }
+      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
+         < (horiz_flag ? window_min_width : window_min_height))
+       {
+         Fset_window_configuration (old_config);
+         error ("Cannot adjust window size as specified");
+       }
+
+      /* Clear out some redisplay caches.  */
+      XSETFASTINT (p->last_modified, 0);
+      XSETFASTINT (p->last_overlay_modified, 0);
+
+      /* Adjust this window's edge.  */
+      XSETINT (CURSIZE (window),
+              XINT (CURSIZE (window)) + delta);
+
+      /* If this window has following siblings in the desired dimension,
+        make them smaller, and exit the loop.
+
+        (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;
+           }
+       }
+      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;
+    }
+
+  /* If we made a window so small it got deleted,
+     we failed.  Report failure.  */
+  if (delcount != window_deletion_count)
+    {
+      Fset_window_configuration (old_config);
+      error ("Cannot adjust window size as specified");
+    }
+
+  /* Adjust glyph matrices. */
+  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
+}
+
 #undef CURBEG
 #undef CURSIZE
 
+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.
+
+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);
+  adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
+  return Qnil;
+}
+
 
 \f
 /***********************************************************************
@@ -4454,7 +4808,7 @@ shrink_mini_window (w)
         among the other windows.  */
       Lisp_Object window;
       XSETWINDOW (window, w);
-      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0, 0);
+      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
     }
 }
 
@@ -4585,11 +4939,10 @@ window_scroll_pixel_based (window, n, whole, noerror)
   struct it it;
   struct window *w = XWINDOW (window);
   struct text_pos start;
-  Lisp_Object tem;
   int this_scroll_margin;
-  int preserve_y;
   /* True if we fiddled the window vscroll field without really scrolling.   */
   int vscrolled = 0;
+  int x, y, rtop, rbot, rowh, vpos;
 
   SET_TEXT_POS_FROM_MARKER (start, w->start);
 
@@ -4597,8 +4950,8 @@ window_scroll_pixel_based (window, n, whole, noerror)
      the screen.  Allow PT to be partially visible, otherwise
      something like (scroll-down 1) with PT in the line before
      the partially visible one would recenter. */
-  tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
-  if (NILP (tem))
+
+  if (!pos_visible_p (w, PT, &x, &y, &rtop, &rbot, &rowh, &vpos))
     {
       /* Move backward half the height of the window.  Performance note:
         vmotion used here is about 10% faster, but would give wrong
@@ -4623,7 +4976,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
     }
   else if (auto_window_vscroll_p)
     {
-      if (tem = XCAR (XCDR (XCDR (tem))), CONSP (tem))
+      if (rtop || rbot)                /* partially visible */
        {
          int px;
          int dy = WINDOW_FRAME_LINE_HEIGHT (w);
@@ -4633,19 +4986,52 @@ window_scroll_pixel_based (window, n, whole, noerror)
                      dy);
          dy *= n;
 
-         if (n < 0 && (px = XINT (XCAR (tem))) > 0)
+         if (n < 0)
            {
-             px = max (0, -w->vscroll - min (px, -dy));
-             Fset_window_vscroll (window, make_number (px), Qt);
-             return;
+             /* Only vscroll backwards if already vscrolled forwards.  */
+             if (w->vscroll < 0 && rtop > 0)
+               {
+                 px = max (0, -w->vscroll - min (rtop, -dy));
+                 Fset_window_vscroll (window, make_number (px), Qt);
+                 return;
+               }
            }
-         if (n > 0 && (px = XINT (XCDR (tem))) > 0)
+         if (n > 0)
            {
-             px = max (0, -w->vscroll + min (px, dy));
-             Fset_window_vscroll (window, make_number (px), Qt);
-             return;
+             /* Do vscroll if already vscrolled or only display line.  */
+             if (rbot > 0 && (w->vscroll < 0 || vpos == 0))
+               {
+                 px = max (0, -w->vscroll + min (rbot, dy));
+                 Fset_window_vscroll (window, make_number (px), Qt);
+                 return;
+               }
+
+             /* Maybe modify window start instead of scrolling.  */
+             if (rbot > 0 || w->vscroll < 0)
+               {
+                 int spos;
+
+                 Fset_window_vscroll (window, make_number (0), Qt);
+                 /* If there are other text lines above the current row,
+                    move window start to current row.  Else to next row. */
+                 if (rbot > 0)
+                   spos = XINT (Fline_beginning_position (Qnil));
+                 else
+                   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;
+                 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;
+                 return;
+               }
            }
        }
+      /* Cancel previous vscroll.  */
       Fset_window_vscroll (window, make_number (0), Qt);
     }
 
@@ -4653,12 +5039,21 @@ window_scroll_pixel_based (window, n, whole, noerror)
      point in the same window line as it is now, so get that line.  */
   if (!NILP (Vscroll_preserve_screen_position))
     {
-      start_display (&it, w, start);
-      move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
-      preserve_y = it.current_y;
+      /* We preserve the goal pixel coordinate across consecutive
+        calls to scroll-up or scroll-down.  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)))
+       {
+         start_display (&it, w, start);
+         move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+         window_scroll_pixel_based_preserve_y = it.current_y;
+       }
     }
   else
-    preserve_y = -1;
+    window_scroll_pixel_based_preserve_y = -1;
 
   /* Move iterator it from start the specified distance forward or
      backward.  The result is the new window start.  */
@@ -4677,7 +5072,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
       if (dy <= 0)
        {
          move_it_vertically_backward (&it, -dy);
-         /* Ensure we actually does move, e.g. in case we are currently
+         /* Ensure we actually do move, e.g. in case we are currently
             looking at an image that is taller that the window height.  */
          while (start_pos == IT_CHARPOS (it)
                 && start_pos > BEGV)
@@ -4687,7 +5082,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
        {
          move_it_to (&it, ZV, -1, it.current_y + dy, -1,
                      MOVE_TO_POS | MOVE_TO_Y);
-         /* Ensure we actually does move, e.g. in case we are currently
+         /* Ensure we actually do move, e.g. in case we are currently
             looking at an image that is taller that the window height.  */
          while (start_pos == IT_CHARPOS (it)
                 && start_pos < ZV)
@@ -4707,7 +5102,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
        {
          if (it.current_y < it.last_visible_y
              && (it.current_y + it.max_ascent + it.max_descent
-                 >= it.last_visible_y))
+                 > it.last_visible_y))
            {
              /* The last line was only partially visible, make it fully
                 visible.  */
@@ -4717,8 +5112,10 @@ window_scroll_pixel_based (window, n, whole, noerror)
            }
          else if (noerror)
            return;
+         else if (n < 0)       /* could happen with empty buffers */
+           xsignal0 (Qbeginning_of_buffer);
          else
-           Fsignal (Qend_of_buffer, Qnil);
+           xsignal0 (Qend_of_buffer);
        }
       else
        {
@@ -4729,7 +5126,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
          else if (noerror)
            return;
          else
-           Fsignal (Qbeginning_of_buffer, Qnil);
+           xsignal0 (Qbeginning_of_buffer);
        }
 
       /* If control gets here, then we vscrolled.  */
@@ -4783,17 +5180,19 @@ window_scroll_pixel_based (window, n, whole, noerror)
       /* We moved the window start towards ZV, so PT may be now
         in the scroll margin at the top.  */
       move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
-      if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin)
+      if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
+          && (NILP (Vscroll_preserve_screen_position)
+             || EQ (Vscroll_preserve_screen_position, Qt)))
        /* We found PT at a legitimate height.  Leave it alone.  */
        ;
-      else if (preserve_y >= 0)
+      else if (window_scroll_pixel_based_preserve_y >= 0)
        {
          /* If we have a header line, take account of it.
             This is necessary because we set it.current_y to 0, above.  */
-         if (WINDOW_WANTS_HEADER_LINE_P (w))
-           preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
-
-         move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+         move_it_to (&it, -1, -1,
+                     window_scroll_pixel_based_preserve_y
+                     - (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0 ),
+                     -1, MOVE_TO_Y);
          SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
        }
       else
@@ -4813,14 +5212,17 @@ window_scroll_pixel_based (window, n, whole, noerror)
       int charpos, bytepos;
       int partial_p;
 
-      /* Save our position, for the preserve_y case.  */
+      /* Save our position, for the
+        window_scroll_pixel_based_preserve_y case.  */
       charpos = IT_CHARPOS (it);
       bytepos = IT_BYTEPOS (it);
 
       /* We moved the window start towards BEGV, so PT may be now
         in the scroll margin at the bottom.  */
       move_it_to (&it, PT, -1,
-                 it.last_visible_y - this_scroll_margin - 1, -1,
+                 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
+                  - this_scroll_margin - 1),
+                 -1,
                  MOVE_TO_POS | MOVE_TO_Y);
 
       /* Save our position, in case it's correct.  */
@@ -4836,23 +5238,20 @@ window_scroll_pixel_based (window, n, whole, noerror)
          partial_p = it.current_y > it.last_visible_y;
        }
 
-      if (charpos == PT && !partial_p)
+      if (charpos == PT && !partial_p
+          && (NILP (Vscroll_preserve_screen_position)
+             || EQ (Vscroll_preserve_screen_position, Qt)))
        /* We found PT before we found the display margin, so PT is ok.  */
        ;
-      else if (preserve_y >= 0)
+      else if (window_scroll_pixel_based_preserve_y >= 0)
        {
          SET_TEXT_POS_FROM_MARKER (start, w->start);
          start_display (&it, w, start);
-#if 0  /* It's wrong to subtract this here
-         because we called start_display again
-         and did not alter it.current_y this time.  */
-
-         /* If we have a header line, take account of it.  */
-         if (WINDOW_WANTS_HEADER_LINE_P (w))
-           preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
-#endif
-
-         move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+         /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
+            here because we called start_display again and did not
+            alter it.current_y this time.  */
+         move_it_to (&it, -1, -1, window_scroll_pixel_based_preserve_y, -1,
+                     MOVE_TO_Y);
          SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
        }
       else
@@ -4928,7 +5327,7 @@ window_scroll_line_based (window, n, whole, noerror)
       if (noerror)
        return;
       else
-       Fsignal (Qbeginning_of_buffer, Qnil);
+       xsignal0 (Qbeginning_of_buffer);
     }
 
   if (pos < ZV)
@@ -4951,7 +5350,8 @@ window_scroll_line_based (window, n, whole, noerror)
         the window-scroll-functions.  */
       w->force_start = Qt;
 
-      if (whole && !NILP (Vscroll_preserve_screen_position))
+      if (!NILP (Vscroll_preserve_screen_position)
+         && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
        {
          SET_PT_BOTH (pos, pos_byte);
          Fvertical_motion (make_number (original_vpos), window);
@@ -5013,7 +5413,7 @@ window_scroll_line_based (window, n, whole, noerror)
       if (noerror)
        return;
       else
-       Fsignal (Qend_of_buffer, Qnil);
+       xsignal0 (Qend_of_buffer);
     }
 }
 
@@ -5326,6 +5726,8 @@ and redisplay normally--don't erase and redraw the frame.  */)
   struct buffer *obuf = current_buffer;
   int center_p = 0;
   int charpos, bytepos;
+  int iarg;
+  int this_scroll_margin;
 
   /* If redisplay is suppressed due to an error, try again.  */
   obuf->display_error_modiff = 0;
@@ -5348,10 +5750,17 @@ and redisplay normally--don't erase and redraw the frame.  */)
     {
       arg = Fprefix_numeric_value (arg);
       CHECK_NUMBER (arg);
+      iarg = XINT (arg);
     }
 
   set_buffer_internal (buf);
 
+  /* Do this after making BUF current
+     in case scroll_margin is buffer-local.  */
+  this_scroll_margin = max (0, scroll_margin);
+  this_scroll_margin = min (this_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
      line counts would lead to strange effects.  */
@@ -5368,14 +5777,16 @@ and redisplay normally--don't erase and redraw the frame.  */)
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
        }
-      else if (XINT (arg) < 0)
+      else if (iarg < 0)
        {
          struct it it;
          struct text_pos pt;
-         int nlines = - XINT (arg);
+         int nlines = -iarg;
          int extra_line_spacing;
          int h = window_box_height (w);
 
+         iarg = - max (-iarg, this_scroll_margin);
+
          SET_TEXT_POS (pt, PT, PT_BYTE);
          start_display (&it, w, pt);
 
@@ -5434,7 +5845,10 @@ and redisplay normally--don't erase and redraw the frame.  */)
       else
        {
          struct position pos;
-         pos = *vmotion (PT, - XINT (arg), w);
+
+         iarg = max (iarg, this_scroll_margin);
+
+         pos = *vmotion (PT, -iarg, w);
          charpos = pos.bufpos;
          bytepos = pos.bytepos;
        }
@@ -5445,11 +5859,15 @@ and redisplay normally--don't erase and redraw the frame.  */)
       int ht = window_internal_height (w);
 
       if (center_p)
-       arg = make_number (ht / 2);
-      else if (XINT (arg) < 0)
-       arg = make_number (XINT (arg) + ht);
+       iarg = ht / 2;
+      else if (iarg < 0)
+       iarg += ht;
+
+      /* Don't let it get into the margin at either top or bottom.  */
+      iarg = max (iarg, this_scroll_margin);
+      iarg = min (iarg, ht - this_scroll_margin - 1);
 
-      pos = *vmotion (PT, - XINT (arg), w);
+      pos = *vmotion (PT, - iarg, w);
       charpos = pos.bufpos;
       bytepos = pos.bytepos;
     }
@@ -5498,6 +5916,9 @@ zero means top of window, negative means relative to bottom of window.  */)
   struct window *w = XWINDOW (selected_window);
   int lines, start;
   Lisp_Object window;
+#if 0
+  int this_scroll_margin;
+#endif
 
   window = selected_window;
   start = marker_position (w->start);
@@ -5513,13 +5934,33 @@ zero means top of window, negative means relative to bottom of window.  */)
     Fgoto_char (w->start);
 
   lines = displayed_window_lines (w);
+
+#if 0
+  this_scroll_margin = max (0, scroll_margin);
+  this_scroll_margin = min (this_scroll_margin, lines / 4);
+#endif
+
   if (NILP (arg))
     XSETFASTINT (arg, lines / 2);
   else
     {
-      arg = Fprefix_numeric_value (arg);
-      if (XINT (arg) < 0)
-       XSETINT (arg, XINT (arg) + lines);
+      int iarg = XINT (Fprefix_numeric_value (arg));
+
+      if (iarg < 0)
+       iarg = iarg + lines;
+
+#if 0  /* This code would prevent move-to-window-line from moving point
+         to a place inside the scroll margins (which would cause the
+         next redisplay to scroll).  I wrote this code, but then concluded
+         it is probably better not to install it.  However, it is here
+         inside #if 0 so as not to lose it.  -- rms.  */
+
+      /* Don't let it get into the margin at either top or bottom.  */
+      iarg = max (iarg, this_scroll_margin);
+      iarg = min (iarg, lines - this_scroll_margin - 1);
+#endif
+
+      arg = make_number (iarg);
     }
 
   /* Skip past a partially visible first line.  */
@@ -5574,10 +6015,9 @@ struct saved_window
   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;
 };
 
-#define SAVED_WINDOW_VECTOR_SIZE 24 /* Arg to Fmake_vector */
-
 #define SAVED_WINDOW_N(swv,n) \
   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
 
@@ -5586,9 +6026,7 @@ DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_
      (object)
      Lisp_Object object;
 {
-  if (WINDOW_CONFIGURATIONP (object))
-    return Qt;
-  return Qnil;
+  return WINDOW_CONFIGURATIONP (object) ? Qt : Qnil;
 }
 
 DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
@@ -5599,8 +6037,7 @@ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_config
   register struct save_window_data *data;
   struct Lisp_Vector *saved_windows;
 
-  if (! WINDOW_CONFIGURATIONP (config))
-    wrong_type_argument (Qwindow_configuration_p, config);
+  CHECK_WINDOW_CONFIGURATION (config);
 
   data = (struct save_window_data *) XVECTOR (config);
   saved_windows = XVECTOR (data->saved_windows);
@@ -5625,8 +6062,7 @@ the return value is nil.  Otherwise the value is t.  */)
   FRAME_PTR f;
   int old_point = -1;
 
-  while (!WINDOW_CONFIGURATIONP (configuration))
-    wrong_type_argument (Qwindow_configuration_p, configuration);
+  CHECK_WINDOW_CONFIGURATION (configuration);
 
   data = (struct save_window_data *) XVECTOR (configuration);
   saved_windows = XVECTOR (data->saved_windows);
@@ -5637,7 +6073,23 @@ the return value is nil.  Otherwise the value is t.  */)
   else
     {
       if (XBUFFER (new_current_buffer) == current_buffer)
-       old_point = PT;
+       /* The code further down "preserves point" by saving here PT in
+          old_point and then setting it later back into PT.  When the
+          current-selected-window and the final-selected-window both show
+          the current buffer, this suffers from the problem that the
+          current PT is the window-point of the current-selected-window,
+          while the final PT is the point of the final-selected-window, so
+          this copy from one PT to the other would end up moving the
+          window-point of the final-selected-window to the window-point of
+          the current-selected-window.  So we have to be careful which
+          point of the current-buffer we copy into old_point.  */
+       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
+           && WINDOWP (selected_window)
+           && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
+           && !EQ (selected_window, data->current_window))
+         old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
+       else
+         old_point = PT;
       else
        /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
           point in new_current_buffer as of the last time this buffer was
@@ -5794,6 +6246,7 @@ the return value is nil.  Otherwise the value is t.  */)
          w->fringes_outside_margins = p->fringes_outside_margins;
          w->scroll_bar_width = p->scroll_bar_width;
          w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
+         w->dedicated = p->dedicated;
          XSETFASTINT (w->last_modified, 0);
          XSETFASTINT (w->last_overlay_modified, 0);
 
@@ -6063,6 +6516,7 @@ save_window_save (window, vector, i)
       p->fringes_outside_margins = w->fringes_outside_margins;
       p->scroll_bar_width = w->scroll_bar_width;
       p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
+      p->dedicated = w->dedicated;
       if (!NILP (w->buffer))
        {
          /* Save w's value of point in the window configuration.
@@ -6157,7 +6611,7 @@ redirection (see `redirect-frame-focus').  */)
   data->saved_windows = tem;
   for (i = 0; i < n_windows; i++)
     XVECTOR (tem)->contents[i]
-      = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
+      = 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);
@@ -6185,6 +6639,84 @@ usage: (save-window-excursion BODY ...)  */)
   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
@@ -6198,33 +6730,33 @@ 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, right)
-     Lisp_Object window, left, right;
+     (window, left_width, right_width)
+     Lisp_Object window, left_width, right_width;
 {
   struct window *w = decode_window (window);
 
   /* Translate negative or zero widths to nil.
      Margins that are too wide have to be checked elsewhere.  */
 
-  if (!NILP (left))
+  if (!NILP (left_width))
     {
-      CHECK_NUMBER (left);
-      if (XINT (left) <= 0)
-       left = Qnil;
+      CHECK_NUMBER (left_width);
+      if (XINT (left_width) <= 0)
+       left_width = Qnil;
     }
 
-  if (!NILP (right))
+  if (!NILP (right_width))
     {
-      CHECK_NUMBER (right);
-      if (XINT (right) <= 0)
-       right = Qnil;
+      CHECK_NUMBER (right_width);
+      if (XINT (right_width) <= 0)
+       right_width = Qnil;
     }
 
-  if (!EQ (w->left_margin_cols, left)
-      || !EQ (w->right_margin_cols, right))
+  if (!EQ (w->left_margin_cols, left_width)
+      || !EQ (w->right_margin_cols, right_width))
     {
-      w->left_margin_cols = left;
-      w->right_margin_cols = right;
+      w->left_margin_cols = left_width;
+      w->right_margin_cols = right_width;
 
       adjust_window_margins (w);
 
@@ -6269,22 +6801,24 @@ 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, right, outside_margins)
-     Lisp_Object window, left, right, outside_margins;
+     (window, left_width, right_width, outside_margins)
+     Lisp_Object window, left_width, right_width, outside_margins;
 {
   struct window *w = decode_window (window);
 
-  if (!NILP (left))
-    CHECK_NATNUM (left);
-  if (!NILP (right))
-    CHECK_NATNUM (right);
+  if (!NILP (left_width))
+    CHECK_NATNUM (left_width);
+  if (!NILP (right_width))
+    CHECK_NATNUM (right_width);
 
-  if (!EQ (w->left_fringe_width, left)
-      || !EQ (w->right_fringe_width, right)
-      || !EQ (w->fringes_outside_margins, outside_margins))
+  /* Do nothing on a tty.  */
+  if (FRAME_WINDOW_P (WINDOW_XFRAME (w))
+      && (!EQ (w->left_fringe_width, left_width)
+         || !EQ (w->right_fringe_width, right_width)
+         || !EQ (w->fringes_outside_margins, outside_margins)))
     {
-      w->left_fringe_width = left;
-      w->right_fringe_width = right;
+      w->left_fringe_width = left_width;
+      w->right_fringe_width = right_width;
       w->fringes_outside_margins = outside_margins;
 
       adjust_window_margins (w);
@@ -6309,10 +6843,11 @@ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
      Lisp_Object window;
 {
   struct window *w = decode_window (window);
+
   return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
                Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
-                      Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ?
-                              Qt : Qnil), Qnil)));
+                      Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                              Qt : Qnil), Qnil)));
 }
 
 
@@ -6330,7 +6865,8 @@ this is automatically adjusted to a multiple of the frame column width.
 Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
 bar: left, right, or nil.
 If WIDTH is nil, use the frame's scroll-bar width.
-If TYPE is t, use the frame's scroll-bar type.  */)
+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;
 {
@@ -6398,7 +6934,7 @@ 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.
 Normally, value is a multiple of the canonical character height of WINDOW;
-optional second arg PIXELS_P means value is measured in pixels.  */)
+optional second arg PIXELS-P means value is measured in pixels.  */)
   (window, pixels_p)
      Lisp_Object window, pixels_p;
 {
@@ -6428,7 +6964,7 @@ DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
        doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
 WINDOW nil means use the selected window.  Normally, VSCROLL is a
 non-negative multiple of the canonical character height of WINDOW;
-optional third arg PIXELS_P non-nil means that VSCROLL is in pixels.
+optional third arg PIXELS-P non-nil means that VSCROLL is in pixels.
 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.
@@ -6483,7 +7019,9 @@ foreach_window (f, fn, user_data)
      int (* fn) P_ ((struct window *, void *));
      void *user_data;
 {
-  foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
+  /* Fdelete_frame may set FRAME_ROOT_WINDOW (f) to Qnil.  */
+  if (WINDOWP (FRAME_ROOT_WINDOW (f)))
+    foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
 }
 
 
@@ -6566,10 +7104,8 @@ compare_window_configurations (c1, c2, ignore_positions)
   struct Lisp_Vector *sw1, *sw2;
   int i;
 
-  if (!WINDOW_CONFIGURATIONP (c1))
-    wrong_type_argument (Qwindow_configuration_p, c1);
-  if (!WINDOW_CONFIGURATIONP (c2))
-    wrong_type_argument (Qwindow_configuration_p, c2);
+  CHECK_WINDOW_CONFIGURATION (c1);
+  CHECK_WINDOW_CONFIGURATION (c2);
 
   d1 = (struct save_window_data *) XVECTOR (c1);
   d2 = (struct save_window_data *) XVECTOR (c2);
@@ -6713,6 +7249,12 @@ init_window ()
 void
 syms_of_window ()
 {
+  Qscroll_up = intern ("scroll-up");
+  staticpro (&Qscroll_up);
+
+  Qscroll_down = intern ("scroll-down");
+  staticpro (&Qscroll_down);
+
   Qwindow_size_fixed = intern ("window-size-fixed");
   staticpro (&Qwindow_size_fixed);
   Fset (Qwindow_size_fixed, Qnil);
@@ -6738,6 +7280,8 @@ syms_of_window ()
   minibuf_selected_window = Qnil;
   staticpro (&minibuf_selected_window);
 
+  window_scroll_pixel_based_preserve_y = -1;
+
   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.
@@ -6900,23 +7444,29 @@ See also `same-window-buffer-names'.  */);
   next_screen_context_lines = 2;
 
   DEFVAR_INT ("split-height-threshold", &split_height_threshold,
-             doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
+             doc: /* *A window must be at least this tall to be eligible for splitting
+by `display-buffer'.  The value is in line units.
 If there is only one window, it is split regardless of this value.  */);
   split_height_threshold = 500;
 
   DEFVAR_INT ("window-min-height", &window_min_height,
-             doc: /* *Delete any window less than this tall (including its mode line).  */);
+             doc: /* *Delete any window less than this tall (including its mode line).
+The value is in line units. */);
   window_min_height = 4;
 
   DEFVAR_INT ("window-min-width", &window_min_width,
-             doc: /* *Delete any window less than this wide.  */);
+             doc: /* *Delete any window less than this wide (measured in characters).  */);
   window_min_width = 10;
 
   DEFVAR_LISP ("scroll-preserve-screen-position",
               &Vscroll_preserve_screen_position,
-              doc: /* *Non-nil means scroll commands move point to keep its screen line unchanged.
-This is only when it is impossible to keep point fixed and still
-scroll as specified.  */);
+              doc: /* *Controls if scroll commands move point to keep its screen line 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.  */);
   Vscroll_preserve_screen_position = Qnil;
 
   DEFVAR_LISP ("window-configuration-change-hook",
@@ -6931,6 +7481,7 @@ The selected frame is the one whose configuration has changed.  */);
   defsubr (&Swindowp);
   defsubr (&Swindow_live_p);
   defsubr (&Spos_visible_in_window_p);
+  defsubr (&Swindow_line_height);
   defsubr (&Swindow_buffer);
   defsubr (&Swindow_height);
   defsubr (&Swindow_width);
@@ -6972,6 +7523,7 @@ The selected frame is the one whose configuration has changed.  */);
   defsubr (&Ssplit_window);
   defsubr (&Senlarge_window);
   defsubr (&Sshrink_window);
+  defsubr (&Sadjust_window_trailing_edge);
   defsubr (&Sscroll_up);
   defsubr (&Sscroll_down);
   defsubr (&Sscroll_left);
@@ -6987,6 +7539,7 @@ The selected frame is the one whose configuration has changed.  */);
   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);