(Fwindow_end): Don't call temp_set_pt_both with
[bpt/emacs.git] / src / window.c
index 5695152..dc01b2f 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 96 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,14 +29,39 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "disptab.h"
 #include "keyboard.h"
+#include "dispextern.h"
+#include "blockinput.h"
+#include "intervals.h"
 
-Lisp_Object Qwindowp, Qwindow_live_p;
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif /* HAVE_X_WINDOWS */
 
-Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
-Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+
+Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
+extern Lisp_Object Qheight, Qwidth;
+
+static struct window *decode_window P_ ((Lisp_Object));
+static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
+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));
+static int window_min_size P_ ((struct window *, int, int, int *));
+static void size_window P_ ((Lisp_Object, int, int, int));
+static void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
+                                 int, int));
+static void freeze_window_start P_ ((struct window *, int));
+static int window_fixed_size_p P_ ((struct window *, int, int));
+static void enlarge_window P_ ((Lisp_Object, int, int));
 
-void delete_all_subwindows ();
-static struct window *decode_window();
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -48,71 +73,107 @@ static struct window *decode_window();
 
 Lisp_Object selected_window;
 
-/* The minibuffer window of the selected frame.
-   Note that you cannot test for minibufferness of an arbitrary window
-   by comparing against this; but you can test for minibufferness of
+/* 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 for C-M-v to scroll
-   when the minibuffer is selected.  */
+   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;
 
 /* If a window gets smaller than either of these, it is removed. */
+
 int window_min_height;
 int window_min_width;
 
 /* Nonzero implies Fdisplay_buffer should create windows. */
+
 int pop_up_windows;
 
 /* Nonzero implies make new frames for Fdisplay_buffer.  */
+
 int pop_up_frames;
 
 /* Non-nil means use this function instead of default */
+
 Lisp_Object Vpop_up_frame_function;
 
 /* Function to call to handle Fdisplay_buffer.  */
+
 Lisp_Object Vdisplay_buffer_function;
 
 /* List of buffer *names* for buffers that should have their own frames.  */
+
 Lisp_Object Vspecial_display_buffer_names;
 
 /* List of regexps for buffer names that should have their own frames.  */
+
 Lisp_Object Vspecial_display_regexps;
 
 /* Function to pop up a special frame.  */
+
 Lisp_Object Vspecial_display_function;
 
 /* List of buffer *names* for buffers to appear in selected window.  */
+
 Lisp_Object Vsame_window_buffer_names;
 
 /* List of regexps for buffer names to appear in selected window.  */
+
 Lisp_Object Vsame_window_regexps;
 
 /* Hook run at end of temp_output_buffer_show.  */
+
 Lisp_Object Qtemp_buffer_show_hook;
 
 /* Fdisplay_buffer always splits the largest window
    if that window is more than this high.  */
+
 int split_height_threshold;
 
 /* Number of lines of continuity in scrolling by screenfuls.  */
+
 int next_screen_context_lines;
 
 /* 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.  */
+
+Lisp_Object Qwindow_configuration_change_hook;
+Lisp_Object Vwindow_configuration_change_hook;
+
+/* Nonzero means scroll commands try to put point
+   at the same screen height as previously.  */
+
+Lisp_Object Vscroll_preserve_screen_position;
+
+#if 0 /* This isn't used anywhere.  */
+/* Nonzero means we can split a frame even if it is "unsplittable".  */
+static int inhibit_frame_unsplittable;
+#endif /* 0 */
+
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
+extern int scroll_margin;
+
 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
 \f
 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
@@ -143,22 +204,34 @@ make_window ()
   for (i = 0; i < VECSIZE (struct window); i++)
     vec->contents[i] = Qnil;
   vec->size = VECSIZE (struct window);
-  p = (struct window *)vec;
+  p = (struct window *) vec;
   XSETFASTINT (p->sequence_number, ++sequence_number);
   XSETFASTINT (p->left, 0);
   XSETFASTINT (p->top, 0);
   XSETFASTINT (p->height, 0);
   XSETFASTINT (p->width, 0);
   XSETFASTINT (p->hscroll, 0);
-  XSETFASTINT (p->last_point_x, 0);
-  XSETFASTINT (p->last_point_y, 0);
+  p->orig_top = p->orig_height = 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->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->phys_cursor_type = -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;
   return val;
 }
 
@@ -177,10 +250,8 @@ used by that frame.")
     Lisp_Object frame;
 {
   if (NILP (frame))
-    XSETFRAME (frame, selected_frame);
-  else
-    CHECK_LIVE_FRAME (frame, 0);
-
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 0);
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
 
@@ -202,12 +273,10 @@ POS defaults to point; WINDOW, to the selected window.")
      Lisp_Object pos, window;
 {
   register struct window *w;
-  register int top;
-  register int height;
   register int posint;
   register struct buffer *buf;
-  struct position posval;
-  int hscroll;
+  struct text_pos top;
+  Lisp_Object in_window;
 
   if (NILP (pos))
     posint = PT;
@@ -218,42 +287,35 @@ POS defaults to point; WINDOW, to the selected window.")
     }
 
   w = decode_window (window);
-  top = marker_position (w->start);
-  hscroll = XINT (w->hscroll);
-
-  if (posint < top)
-    return Qnil;
-
-  height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
-
   buf = XBUFFER (w->buffer);
-  if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
-      && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf))
-    {
-      /* If frame is up to date,
-        use the info recorded about how much text fit on it. */
-      if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
-         || (XFASTINT (w->window_end_vpos) < height))
-       return Qt;
-      return Qnil;
-    }
+  SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+  /* If position above window, it's not visible.  */
+  if (posint < CHARPOS (top))
+    in_window = Qnil;
+  else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
+      && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
+      && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
+    /* If frame is up to date, and POSINT is < window end pos, use
+       that info.  This doesn't work for POSINT == end pos, because
+       the window end pos is actually the position _after_ the last
+       char in the window.  */
+    in_window = Qt;
+  else if (posint > BUF_ZV (buf))
+    in_window = Qnil;
+  else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
+    /* If window start is out of range, do something reasonable.  */
+    in_window = Qnil;
   else
     {
-      if (posint > BUF_ZV (buf))
-       return Qnil;
-
-      /* w->start can be out of range.  If it is, do something reasonable.  */
-      if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
-       return Qnil;
-
-      /* If that info is not correct, calculate afresh */
-      posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0), 0,
-                               posint, height, 0,
-                               window_internal_width (w) - 1,
-                               hscroll, 0, w);
-
-      return posval.vpos < height ? Qt : Qnil;
+      struct it it;
+      start_display (&it, w, top);
+      move_it_to (&it, posint, 0, it.last_visible_y, -1,
+                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+      in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
     }
+
+  return in_window;
 }
 \f
 static struct window *
@@ -314,7 +376,8 @@ NCOL should be zero or positive.")
   if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
   w = decode_window (window);
   if (XINT (w->hscroll) != XINT (ncol))
-    XBUFFER (w->buffer)->clip_changed = 1; /* Prevent redisplay shortcuts */
+    /* Prevent redisplay shortcuts */
+    XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
   w->hscroll = ncol;
   return ncol;
 }
@@ -359,13 +422,13 @@ and BOTTOM is one more than the bottommost row used by WINDOW\n\
   register struct window *w = decode_window (window);
 
   return Fcons (w->left, Fcons (w->top,
-           Fcons (make_number (XFASTINT (w->left) + XFASTINT (w->width)),
+           Fcons (make_number (WINDOW_RIGHT_EDGE (w)),
                  Fcons (make_number (XFASTINT (w->top)
                                      + XFASTINT (w->height)),
                         Qnil))));
 }
 
-/* Test if the character at column *x, row *y is within window *w.
+/* Test if the character at column *X, row *Y is within window W.
    If it is not, return 0;
    if it is in the window's text area,
       set *x and *y to its location relative to the upper left corner
@@ -373,34 +436,77 @@ and BOTTOM is one more than the bottommost row used by WINDOW\n\
       return 1;
    if it is on the window's modeline, return 2;
    if it is on the border between the window and its right sibling,
-      return 3.  */
+      return 3.
+   if it is on the window's top line, return 4;
+   if it is in the bitmap area to the left/right of the window,
+   return 5 or 6, and convert *X and *Y to window-relative corrdinates.
+
+   X and Y are frame relative pixel coordinates.  */
+
 static int
 coordinates_in_window (w, x, y)
      register struct window *w;
      register int *x, *y;
 {
-  register int left = XINT (w->left);
-  register int width = XINT (w->width);
-  register int window_height = XINT (w->height);
-  register int top = XFASTINT (w->top);
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int left_x, right_x, top_y, bottom_y;
+  int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
 
-  if (   *x < left || *x >= left + width
-      || *y < top  || *y >= top  + window_height)
-    return 0;
+  if (w->pseudo_window_p)
+    {
+      left_x = 0;
+      right_x = XFASTINT (w->width) * CANON_Y_UNIT (f);
+      top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
+      bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
+    }
+  else
+    {
+      left_x = WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
+      right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w);
+      top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
+      bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
+    }
 
-  /* Is the character is the mode line?  */
-  if (*y == top + window_height - 1
-      && ! MINI_WINDOW_P (w))
+  if (*y < top_y
+      || *y >= bottom_y
+      || *x < (left_x
+              - flags_area_width
+              - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
+                 * CANON_X_UNIT (f)))
+      || *x > right_x + flags_area_width)
+    /* Completely outside anything interesting.  */
+    return 0;
+  else if (WINDOW_WANTS_MODELINE_P (w)
+          && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+    /* On the mode line.  */
     return 2;
-
-  /* Is the character in the right border?  */
-  if (*x == left + width - 1
-      && left + width != FRAME_WIDTH (XFRAME (w->frame)))
+  else if (WINDOW_WANTS_HEADER_LINE_P (w)
+          && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+    /* On the top line.  */
+    return 4;
+  else if (*x < left_x || *x >= right_x)
+    {
+      /* Other lines than the mode line don't include flags areas and
+        scroll bars on the left.  */
+      
+      /* Convert X and Y to window-relative pixel coordinates.  */
+      *x -= left_x;
+      *y -= top_y;
+      return *x < left_x ? 5 : 6;
+    }
+  else if (!w->pseudo_window_p
+          && !WINDOW_RIGHTMOST_P (w)
+          && *x >= right_x - CANON_X_UNIT (f))
+    /* On the border on the right side of the window?  Assume that
+       this area begins at RIGHT_X minus a canonical char width.  */
     return 3;
-
-  *x -= left;
-  *y -= top;
-  return 1;
+  else
+    {
+      /* Convert X and Y to window-relative pixel coordinates.  */
+      *x -= left_x;
+      *y -= top_y;
+      return 1;
+    }
 }
 
 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
@@ -413,25 +519,42 @@ frame.\n\
 If COORDINATES are in the text portion of WINDOW,\n\
    the coordinates relative to the window are returned.\n\
 If they are in the mode line of WINDOW, `mode-line' is returned.\n\
+If they are in the top mode line of WINDOW, `header-line' is returned.\n\
+If they are in the bitmap-area to the left of the window,\n\
+   `left-bitmap-area' is returned, if they are in the area on the right of\n\
+   the window, `right-bitmap-area' is returned.\n\
 If they are on the border between WINDOW and its right sibling,\n\
    `vertical-line' is returned.")
   (coordinates, window)
      register Lisp_Object coordinates, window;
 {
+  struct window *w;
+  struct frame *f;
   int x, y;
+  Lisp_Object lx, ly;
 
   CHECK_LIVE_WINDOW (window, 0);
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
   CHECK_CONS (coordinates, 1);
-  x = XINT (Fcar (coordinates));
-  y = XINT (Fcdr (coordinates));
-
-  switch (coordinates_in_window (XWINDOW (window), &x, &y))
+  lx = Fcar (coordinates);
+  ly = Fcdr (coordinates);
+  CHECK_NUMBER_OR_FLOAT (lx, 1);
+  CHECK_NUMBER_OR_FLOAT (ly, 1);
+  x = PIXEL_X_FROM_CANON_X (f, lx);
+  y = PIXEL_Y_FROM_CANON_Y (f, ly);
+
+  switch (coordinates_in_window (w, &x, &y))
     {
     case 0:                    /* NOT in window at all. */
       return Qnil;
 
     case 1:                    /* In text part of window. */
-      return Fcons (x, y);
+      /* X and Y are now window relative pixel coordinates.
+        Convert them to canonical char units before returning
+        them.  */
+      return Fcons (CANON_X_FROM_PIXEL_X (f, x), 
+                   CANON_Y_FROM_PIXEL_Y (f, y));
 
     case 2:                    /* In mode line of window. */
       return Qmode_line;
@@ -439,29 +562,42 @@ If they are on the border between WINDOW and its right sibling,\n\
     case 3:                    /* On right border of window.  */
       return Qvertical_line;
 
+    case 4:
+      return Qheader_line;
+
+    case 5:
+      return Qleft_bitmap_area;
+      
+    case 6:
+      return Qright_bitmap_area;
+
     default:
       abort ();
     }
 }
 
-/* Find the window containing column x, row y, and return it as a
-   Lisp_Object.  If x, y is on the window's modeline, set *part
-   to 1; if it is on the separating line between the window and its
-   right sibling, set it to 2; otherwise set it to 0.  If there is no
-   window under x, y return nil and leave *part unmodified.  */
+/* Find the window containing frame-relative pixel position X/Y and
+   return it as a Lisp_Object.  If X, Y is on the window's modeline,
+   set *PART to 1; if it is on the separating line between the window
+   and its right sibling, set it to 2; otherwise set it to 0.  If
+   there is no window under X, Y return nil and leave *PART
+   unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.  */
+
 Lisp_Object
-window_from_coordinates (frame, x, y, part)
+window_from_coordinates (frame, x, y, part, tool_bar_p)
      FRAME_PTR frame;
      int x, y;
      int *part;
+     int tool_bar_p;
 {
   register Lisp_Object tem, first;
+  int found;
 
   tem = first = FRAME_SELECTED_WINDOW (frame);
 
   do
     {
-      int found = coordinates_in_window (XWINDOW (tem), &x, &y);
+      found = coordinates_in_window (XWINDOW (tem), &x, &y);
 
       if (found)
        {
@@ -471,7 +607,17 @@ window_from_coordinates (frame, x, y, part)
 
       tem = Fnext_window (tem, Qt, Qlambda);
     }
-  while (! EQ (tem, first));
+  while (!EQ (tem, first));
+
+  /* See if it's in the tool bar window, if a tool bar exists.  */
+  if (tool_bar_p
+      && WINDOWP (frame->tool_bar_window)
+      && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
+      && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
+    {
+      *part = 0;
+      return frame->tool_bar_window;
+    }
 
   return Qnil;
 }
@@ -485,17 +631,21 @@ column 0.")
       Lisp_Object x, y, frame;
 {
   int part;
+  struct frame *f;
 
   if (NILP (frame))
-    XSETFRAME (frame, selected_frame);
-  else
-    CHECK_LIVE_FRAME (frame, 2);
-  CHECK_NUMBER (x, 0);
-  CHECK_NUMBER (y, 1);
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 2);
+  f = XFRAME (frame);
+
+  /* Check that arguments are integers or floats.  */
+  CHECK_NUMBER_OR_FLOAT (x, 0);
+  CHECK_NUMBER_OR_FLOAT (y, 1);
 
-  return window_from_coordinates (XFRAME (frame),
-                                 XINT (x), XINT (y),
-                                 &part);
+  return window_from_coordinates (f, 
+                                 PIXEL_X_FROM_CANON_X (f, x),
+                                 PIXEL_Y_FROM_CANON_Y (f, y),
+                                 &part, 0);
 }
 
 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
@@ -539,13 +689,15 @@ have been if redisplay had finished, do this:\n\
       (vertical-motion (1- (window-height window)) window)\n\
       (point))")  */
 
-DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
+DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
   "Return position at which display currently ends in WINDOW.\n\
 This is updated by redisplay, when it runs to completion.\n\
 Simply changing the buffer text or setting `window-start'\n\
-does not update this value.")
-  (window)
-     Lisp_Object window;
+does not update this value.\n\
+If UP-TO-DATE is non-nil, compute the up-to-date position\n\
+if it isn't already recorded.")
+  (window, update)
+     Lisp_Object window, update;
 {
   Lisp_Object value;
   struct window *w = decode_window (window);
@@ -563,8 +715,33 @@ does not update this value.")
     return Qnil;
 #endif
 
-  XSETINT (value,
-          BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+  if (! NILP (update)
+      && ! (! NILP (w->window_end_valid)
+           && XFASTINT (w->last_modified) >= MODIFF))
+    {
+      int opoint = PT, opoint_byte = PT_BYTE;
+
+      /* In case W->start is out of the range, use something
+         reasonable.  This situation occured when loading a file with
+         `-l' containing a call to `rmail' with subsequent other
+         commands.  At the end, W->start happened to be BEG, while
+         rmail had already narrowed the buffer.  This leads to an
+         abort in temp_set_pt_both.  */
+      if (XMARKER (w->start)->charpos < BEGV)
+       TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+      else if (XMARKER (w->start)->charpos > ZV)
+       TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+      else
+       TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
+                         XMARKER (w->start)->bytepos);
+      
+      Fvertical_motion (make_number (window_internal_height (w)), Qnil);
+      XSETINT (value, PT);
+      TEMP_SET_PT_BOTH (opoint, opoint_byte);
+    }
+  else
+    XSETINT (value,
+            BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
 
   return value;
 }
@@ -577,11 +754,12 @@ DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
   register struct window *w = decode_window (window);
 
   CHECK_NUMBER_COERCE_MARKER (pos, 1);
-  if (w == XWINDOW (selected_window))
+  if (w == XWINDOW (selected_window)
+      && XBUFFER (w->buffer) == current_buffer)
     Fgoto_char (pos);
   else
     set_marker_restricted (w->pointm, pos, w->buffer);
-
+  
   return pos;
 }
 
@@ -605,6 +783,7 @@ from overriding motion of point in order to display at this exact start.")
   XSETFASTINT (w->last_overlay_modified, 0);
   if (!EQ (window, selected_window))
     windows_or_buffers_changed++;
+
   return pos;
 }
 
@@ -647,10 +826,10 @@ DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
   return decode_window (window)->display_table;
 }
 
-/* Get the display table for use currently on window W.
-   This is either W's display table or W's buffer's display table.
-   Ignore the specified tables if they are not valid;
-   if no valid table is specified, return 0.  */
+/* Get the display table for use on window W.  This is either W's
+   display table or W's buffer's display table.  Ignore the specified
+   tables if they are not valid; if no valid table is specified,
+   return 0.  */
 
 struct Lisp_Char_Table *
 window_display_table (w)
@@ -660,6 +839,9 @@ window_display_table (w)
   tem = w->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
+  if (NILP (w->buffer))
+    return 0;
+
   tem = XBUFFER (w->buffer)->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
@@ -675,7 +857,6 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
      register Lisp_Object window, table;
 {
   register struct window *w;
-  register Lisp_Object z;      /* Return value. */
 
   w = decode_window (window);
   w->display_table = table;
@@ -684,18 +865,20 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
 \f
 /* Record info on buffer window w is displaying
    when it is about to cease to display that buffer.  */
-static
+static void
 unshow_buffer (w)
      register struct window *w;
 {
   Lisp_Object buf;
+  struct buffer *b;
 
   buf = w->buffer;
-  if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
+  b = XBUFFER (buf);
+  if (b != XMARKER (w->pointm)->buffer)
     abort ();
 
-  if (w == XWINDOW (XBUFFER (buf)->last_selected_window))
-    XBUFFER (buf)->last_selected_window = Qnil;
+  if (w == XWINDOW (b->last_selected_window))
+    b->last_selected_window = Qnil;
 
 #if 0
   if (w == XWINDOW (selected_window)
@@ -710,20 +893,23 @@ unshow_buffer (w)
        selected window, while last_window_start reflects another
        window which was recently showing the same buffer.
        Some people might say that might be a good thing.  Let's see.  */
-    XBUFFER (buf)->last_window_start = marker_position (w->start);
+    b->last_window_start = marker_position (w->start);
 
   /* Point in the selected window's buffer
      is actually stored in that buffer, and the window's pointm isn't used.
      So don't clobber point in that buffer.  */
   if (! EQ (buf, XWINDOW (selected_window)->buffer))
-    BUF_PT (XBUFFER (buf))
-      = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
-                       marker_position (w->pointm),
-                       BUF_ZV (XBUFFER (buf)));
+    temp_set_point_both (b,
+                        clip_to_bounds (BUF_BEGV (b),
+                                        XMARKER (w->pointm)->charpos,
+                                        BUF_ZV (b)),
+                        clip_to_bounds (BUF_BEGV_BYTE (b),
+                                        marker_byte_position (w->pointm),
+                                        BUF_ZV_BYTE (b)));
 }
 
 /* Put replacement into the window structure in place of old. */
-static
+static void
 replace_window (old, replacement)
      Lisp_Object old, replacement;
 {
@@ -740,6 +926,19 @@ replace_window (old, replacement)
   p->top = o->top;
   p->width = o->width;
   p->height = o->height;
+  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->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 = p->orig_height = Qnil;
 
   p->next = tem = o->next;
   if (!NILP (tem))
@@ -767,10 +966,24 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   "Remove WINDOW from the display.  Default is selected window.")
   (window)
      register Lisp_Object window;
+{
+  delete_window (window);
+
+  if (! NILP (Vwindow_configuration_change_hook)
+      && ! NILP (Vrun_hooks))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
+  return Qnil;
+}
+
+void
+delete_window (window)
+     register Lisp_Object window;
 {
   register Lisp_Object tem, parent, sib;
   register struct window *p;
   register struct window *par;
+  FRAME_PTR frame;
 
   /* Because this function is called by other C code on non-leaf
      windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
@@ -785,7 +998,7 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   if (NILP (p->buffer)
       && NILP (p->hchild)
       && NILP (p->vchild))
-    return Qnil;
+    return;
 
   parent = p->parent;
   if (NILP (parent))
@@ -793,7 +1006,8 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   par = XWINDOW (parent);
 
   windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (p))) = 1;
+  frame = XFRAME (WINDOW_FRAME (p));
+  FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
 
   /* Are we trying to delete any frame's selected window?  */
   {
@@ -839,6 +1053,11 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
       unchain_marker (p->start);
     }
 
+  /* Free window glyph matrices.
+     It is sure that they are allocated again when ADJUST_GLYPHS
+     is called. */
+  free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
+
   tem = p->next;
   if (!NILP (tem))
     XWINDOW (tem)->prev = p->prev;
@@ -893,7 +1112,8 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   /* Mark this window as deleted.  */
   p->buffer = p->hchild = p->vchild = Qnil;
 
-  return Qnil;
+  /* Adjust glyph matrices. */
+  adjust_glyphs (frame);
 }
 \f
 
@@ -1006,7 +1226,7 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
                   If that happens, go back to the selected frame
                   so we can complete the cycle.  */
                if (EQ (tem, tem1))
-                 XSETFRAME (tem, selected_frame);
+                 tem = selected_frame;
              }
            tem = FRAME_ROOT_WINDOW (XFRAME (tem));
 
@@ -1025,6 +1245,8 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
            window = XWINDOW (window)->vchild;
          else break;
        }
+
+      QUIT;
     }
   /* Which windows are acceptable?
      Exit the loop and accept this window if
@@ -1158,7 +1380,7 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
                   If that happens, go back to the selected frame
                   so we can complete the cycle.  */
                if (EQ (tem, tem1))
-                 XSETFRAME (tem, selected_frame);
+                 tem = selected_frame;
              }
            /* If this frame has a minibuffer, find that window first,
               because it is conceptually the last window in that frame.  */
@@ -1245,7 +1467,8 @@ enum window_loop
   DELETE_OTHER_WINDOWS,                /* Arg is window not to delete */
   DELETE_BUFFER_WINDOWS,       /* Arg is buffer */
   GET_LARGEST_WINDOW,
-  UNSHOW_BUFFER                /* Arg is buffer */
+  UNSHOW_BUFFER,               /* Arg is buffer */
+  CHECK_ALL_WINDOWS
 };
 
 static Lisp_Object
@@ -1268,7 +1491,7 @@ window_loop (type, obj, mini, frames)
   if (FRAMEP (frames))
     frame = XFRAME (frames);
   else if (NILP (frames))
-    frame = selected_frame;
+    frame = SELECTED_FRAME ();
   else
     frame = 0;
   if (frame)
@@ -1288,7 +1511,7 @@ window_loop (type, obj, mini, frames)
   else if (frame)
     w = FRAME_SELECTED_WINDOW (frame);
   else
-    w = FRAME_SELECTED_WINDOW (selected_frame);
+    w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
 
   /* Figure out the last window we're going to mess with.  Since
      Fnext_window, given the same options, is guaranteed to go in a
@@ -1302,8 +1525,6 @@ window_loop (type, obj, mini, frames)
   best_window = Qnil;
   for (;;)
     {
-      FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-
       /* Pick the next window now, since some operations will delete
         the current window.  */
       next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
@@ -1312,18 +1533,23 @@ window_loop (type, obj, mini, frames)
         the frame is visible, since Fnext_window skips non-visible frames
         if that is desired, under the control of frame_arg.  */
       if (! MINI_WINDOW_P (XWINDOW (w))
+         /* For UNSHOW_BUFFER, we must always consider all windows.  */
+         || type == UNSHOW_BUFFER
          || (mini && minibuf_level > 0))
        switch (type)
          {
          case GET_BUFFER_WINDOW:
-           if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj))
+           if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
+               /* Don't find any minibuffer window
+                  except the one that is currently in use.  */
+               && (MINI_WINDOW_P (XWINDOW (w))
+                   ? EQ (w, minibuf_window) : 1))
              return w;
            break;
 
          case GET_LRU_WINDOW:
            /* t as arg means consider only full-width windows */
-           if (!NILP (obj) && XFASTINT (XWINDOW (w)->width)
-               != FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (w)))))
+           if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (XWINDOW (w)))
              break;
            /* Ignore dedicated windows and minibuffers.  */
            if (MINI_WINDOW_P (XWINDOW (w))
@@ -1376,7 +1602,8 @@ window_loop (type, obj, mini, frames)
                  if (NILP (XWINDOW (w)->parent))
                    {
                      Lisp_Object new_buffer;
-                     new_buffer = Fother_buffer (obj, Qnil);
+                     new_buffer = Fother_buffer (obj, Qnil,
+                                                 XWINDOW (w)->frame);
                      if (NILP (new_buffer))
                        new_buffer
                          = Fget_buffer_create (build_string ("*scratch*"));
@@ -1411,7 +1638,7 @@ window_loop (type, obj, mini, frames)
                /* Find another buffer to show in this window.  */
                Lisp_Object another_buffer;
                FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-               another_buffer = Fother_buffer (obj, Qnil);
+               another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
                if (NILP (another_buffer))
                  another_buffer
                    = Fget_buffer_create (build_string ("*scratch*"));
@@ -1450,6 +1677,12 @@ window_loop (type, obj, mini, frames)
                  }
              }
            break;
+
+           /* Check for a window that has a killed buffer.  */
+         case CHECK_ALL_WINDOWS:
+           if (! NILP (XWINDOW (w)->buffer)
+               && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
+             abort ();
          }
 
       if (EQ (w, last_window))
@@ -1461,6 +1694,14 @@ window_loop (type, obj, mini, frames)
   return best_window;
 }
 
+/* Used for debugging.  Abort if any window has a dead buffer.  */
+
+void
+check_all_windows ()
+{
+  window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
+}
+
 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
   "Return the window least recently selected or used for display.\n\
 If optional argument FRAME is `visible', search all visible frames.\n\
@@ -1536,7 +1777,7 @@ value is reasonable when this function is called.")
   w = XWINDOW (window);
 
   startpos = marker_position (w->start);
-  top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
+  top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
 
   if (MINI_WINDOW_P (w) && top > 0)
     error ("Can't expand minibuffer to full frame");
@@ -1558,16 +1799,18 @@ value is reasonable when this function is called.")
       /* This computation used to temporarily move point, but that can
         have unwanted side effects due to text properties.  */
       pos = *vmotion (startpos, -top, w);
-      Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
-      w->start_at_line_beg = ((pos.bufpos == BEGV
-                              || FETCH_CHAR (pos.bufpos - 1) == '\n') ? Qt
+
+      set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+      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->force_start = Qt;
+      w->optional_new_start = Qt;
 
       set_buffer_internal (obuf);
     }
+
   return Qnil;
 }
 
@@ -1575,17 +1818,20 @@ DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
   1, 2, "bDelete windows on (buffer): ",
   "Delete all windows showing BUFFER.\n\
 Optional second argument FRAME controls which frames are affected.\n\
-If nil or omitted, delete all windows showing BUFFER in any frame.\n\
-If t, delete only windows showing BUFFER in the selected frame.\n\
-If `visible', delete all windows showing BUFFER in any visible frame.\n\
-If a frame, delete only windows showing BUFFER in that frame.")
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is nil, search all frames.\n\
+If FRAME is t, search only the selected frame.\n\
+If FRAME is a frame, search only that frame.")
   (buffer, frame)
      Lisp_Object buffer, frame;
 {
   /* FRAME uses t and nil to mean the opposite of what window_loop
      expects.  */
-  if (! FRAMEP (frame))
-    frame = NILP (frame) ? Qt : Qnil;
+  if (NILP (frame))
+    frame = Qt;
+  else if (EQ (frame, Qt))
+    frame = Qnil;
 
   if (!NILP (buffer))
     {
@@ -1593,6 +1839,7 @@ If a frame, delete only windows showing BUFFER in that frame.")
       CHECK_BUFFER (buffer, 0);
       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
     }
+  
   return Qnil;
 }
 
@@ -1626,9 +1873,9 @@ replace_buffer_in_all_windows (buffer)
      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, 0, frame);
+    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
 #else
-  window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
+  window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
 #endif
 }
 \f
@@ -1636,6 +1883,7 @@ replace_buffer_in_all_windows (buffer)
 
 /* The smallest acceptable dimensions for a window.  Anything smaller
    might crash Emacs.  */
+
 #define MIN_SAFE_WINDOW_WIDTH  (2)
 #define MIN_SAFE_WINDOW_HEIGHT (2)
 
@@ -1654,6 +1902,7 @@ check_min_window_sizes ()
 
 /* 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;
@@ -1667,8 +1916,9 @@ check_frame_size (frame, rows, cols)
     (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
      : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
      : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
-  if (FRAME_MENU_BAR_LINES (frame) > 0)
-    min_height += FRAME_MENU_BAR_LINES (frame);
+  
+  if (FRAME_TOP_MARGIN (frame) > 0)
+    min_height += FRAME_TOP_MARGIN (frame);
 
   if (*rows < min_height)
     *rows = min_height;
@@ -1676,191 +1926,466 @@ check_frame_size (frame, rows, cols)
     *cols = MIN_SAFE_WINDOW_WIDTH;
 }
 
-/* Normally the window is deleted if it gets too small.
-   nodelete nonzero means do not do this.
-   (The caller should check later and do so if appropriate)  */
 
-set_window_height (window, height, nodelete)
-     Lisp_Object window;
-     int height;
-     int nodelete;
+/* 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.  */
+
+static int
+window_fixed_size_p (w, width_p, check_siblings_p)
+     struct window *w;
+     int width_p, check_siblings_p;
 {
-  register struct window *w = XWINDOW (window);
-  register struct window *c;
-  int oheight = XFASTINT (w->height);
-  int top, pos, lastbot, opos, lastobot;
-  Lisp_Object child;
+  int fixed_p;
+  struct window *c;
+  
+  if (!NILP (w->hchild))
+    {
+      c = XWINDOW (w->hchild);
+      
+      if (width_p)
+       {
+         /* A horiz. 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 horiz. 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;
+       }
+    }
+  else if (!NILP (w->vchild))
+    {
+      c = XWINDOW (w->vchild);
+      
+      if (width_p)
+       {
+         /* A vert. 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
+       {
+         /* A vert. 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;
+       }
+    }
+  else if (BUFFERP (w->buffer))
+    {
+      if (w->height_fixed_p && !width_p)
+       fixed_p = 1;
+      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))
+           {
+             fixed_p = !NILP (val);
+             
+             if (fixed_p
+                 && ((EQ (val, Qheight) && width_p)
+                     || (EQ (val, Qwidth) && !width_p)))
+               fixed_p = 0;
+           }
+       }
 
-  check_min_window_sizes ();
+      /* 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))
+       {
+         Lisp_Object child;
+         
+         for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
+           if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+             break;
 
-  if (!nodelete
-      && ! NILP (w->parent)
-      && height < window_min_height)
-    {
-      Fdelete_window (window);
-      return;
+         if (NILP (child))
+           for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
+             if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+               break;
+
+         if (NILP (child))
+           fixed_p = 1;
+       }
     }
+  else
+    fixed_p = 1;
 
-  XSETFASTINT (w->last_modified, 0);
-  XSETFASTINT (w->last_overlay_modified, 0);
-  windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+  return fixed_p;
+}
+  
 
-  XSETFASTINT (w->height, height);
+/* Return the 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.  If W is a combination window,
+   compute the minimum size from the minimum sizes of W's children.  */
+
+static int
+window_min_size_1 (w, width_p)
+     struct window *w;
+     int width_p;
+{
+  struct window *c;
+  int size;
+  
   if (!NILP (w->hchild))
     {
-      for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+      c = XWINDOW (w->hchild);
+      size = 0;
+      
+      if (width_p)
+       {
+         /* The min width of a horizontal combination is
+            the sum of the min widths of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+      else
        {
-         XWINDOW (child)->top = w->top;
-         set_window_height (child, height, nodelete);
+         /* The min height a horizontal combination equals
+            the maximum of all min height of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
        }
     }
   else if (!NILP (w->vchild))
     {
-      lastbot = top = XFASTINT (w->top);
-      lastobot = 0;
-      for (child = w->vchild; !NILP (child); child = c->next)
+      c = XWINDOW (w->vchild);
+      size = 0;
+      
+      if (width_p)
        {
-         c = XWINDOW (child);
+         /* The min width of a vertical combination is
+            the maximum of the min widths of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+      else
+       {
+         /* The min height of a vertical combination equals
+            the sum of the min height of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+    }
+  else
+    {
+      if (width_p)
+       size = window_min_width;
+      else
+       {
+         if (MINI_WINDOW_P (w)
+             || (!WINDOW_WANTS_MODELINE_P (w)
+                 && !WINDOW_WANTS_HEADER_LINE_P (w)))
+           size = 1;
+         else
+           size = window_min_height;
+       }
+    }
 
-         opos = lastobot + XFASTINT (c->height);
+  return size;
+}
 
-         XSETFASTINT (c->top, lastbot);
 
-         pos = (((opos * height) << 1) + oheight) / (oheight << 1);
+/* 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.  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.  */
 
-         /* Avoid confusion: inhibit deletion of child if becomes too small */
-         set_window_height (child, pos + top - lastbot, 1);
+static int
+window_min_size (w, width_p, ignore_fixed_p, fixed)
+     struct window *w;
+     int width_p, ignore_fixed_p, *fixed;
+{
+  int size, fixed_p;
 
-         /* Now advance child to next window,
-            and set lastbot if child was not just deleted.  */
-         lastbot = pos + top;
-         lastobot = opos;
-       }
-      /* Now delete any children that became too small.  */
-      if (!nodelete)
-       for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
-         {
-           set_window_height (child, XINT (XWINDOW (child)->height), 0);
-         }
-    }
+  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 = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
+  else
+    size = window_min_size_1 (w, width_p);
+      
+  return size;
 }
 
-/* Recursively set width of WINDOW and its inferiors. */
 
-set_window_width (window, width, nodelete)
+/* 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.  */
+
+static void
+size_window (window, size, width_p, nodelete_p)
      Lisp_Object window;
-     int width;
-     int nodelete;
+     int size, width_p, nodelete_p;
 {
-  register struct window *w = XWINDOW (window);
-  register struct window *c;
-  int owidth = XFASTINT (w->width);
-  int left, pos, lastright, opos, lastoright;
-  Lisp_Object child;
+  struct window *w = XWINDOW (window);
+  struct window *c;
+  Lisp_Object child, *forward, *sideward;
+  int old_size, min_size;
 
-  if (!nodelete && width < window_min_width && !NILP (w->parent))
+  check_min_window_sizes ();
+  
+  /* If the window has been "too small" at one point,
+     don't delete it for being "too small" in the future.
+     Preserve it as long as that is at all possible.  */
+  if (width_p)
     {
-      Fdelete_window (window);
-      return;
+      old_size = XFASTINT (w->width);
+      min_size = window_min_width;
+    }
+  else
+    {
+      old_size = XFASTINT (w->height);
+      min_size = window_min_height;
+    }
+  
+  if (old_size < window_min_width)
+    w->too_small_ok = Qt;
+
+  /* Maybe delete WINDOW if it's too small.  */
+  if (!nodelete_p && !NILP (w->parent))
+    {
+      int min_size;
+
+      if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
+       min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
+      else
+       min_size = width_p ? window_min_width : window_min_height;
+      
+      if (size < min_size)
+       {
+         delete_window (window);
+         return;
+       }
     }
 
+  /* 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;
 
-  XSETFASTINT (w->width, width);
-  if (!NILP (w->vchild))
+  if (width_p)
     {
-      for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
+      sideward = &w->vchild;
+      forward = &w->hchild;
+      XSETFASTINT (w->width, size);
+    }
+  else
+    {
+      sideward = &w->hchild;
+      forward = &w->vchild;
+      XSETFASTINT (w->height, size);
+    }
+
+  if (!NILP (*sideward))
+    {
+      for (child = *sideward; !NILP (child); child = c->next)
        {
-         XWINDOW (child)->left = w->left;
-         set_window_width (child, width, nodelete);
+         c = XWINDOW (child);
+         if (width_p)
+           c->left = w->left;
+         else
+           c->top = w->top;
+         size_window (child, size, width_p, nodelete_p);
        }
     }
-  else if (!NILP (w->hchild))
+  else if (!NILP (*forward))
     {
-      lastright = left = XFASTINT (w->left);
-      lastoright = 0;
-      for (child = w->hchild; !NILP (child); child = c->next)
+      int fixed_size, each, extra, n;
+      int resize_fixed_p, nfixed;
+      int last_pos, first_pos, nchildren;
+
+      /* Determine the fixed-size portion of the this window, and the
+        number of child windows.  */
+      fixed_size = nchildren = nfixed = 0;
+      for (child = *forward; !NILP (child); child = c->next, ++nchildren)
        {
          c = XWINDOW (child);
+         if (window_fixed_size_p (c, width_p, 0))
+           {
+             fixed_size += (width_p
+                            ? XFASTINT (c->width) : XFASTINT (c->height));
+             ++nfixed;
+           }
+       }
 
-         opos = lastoright + XFASTINT (c->width);
-
-         XSETFASTINT (c->left, lastright);
-
-         pos = (((opos * width) << 1) + owidth) / (owidth << 1);
+      /* 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 to each child.  The
+        value of extra takes care of rounding errors.  */
+      n = resize_fixed_p ? nchildren : nchildren - nfixed;
+      each = (size - old_size) / n;
+      extra = (size - old_size) - n * each;
+
+      /* Compute new children heights and edge positions.  */
+      first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
+      last_pos = first_pos;
+      for (child = *forward; !NILP (child); child = c->next)
+       {
+         int new_size, old_size;
+         
+         c = XWINDOW (child);
+         old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+         new_size = old_size;
 
-         /* Inhibit deletion for becoming too small */
-         set_window_width (child, pos + left - lastright, 1);
+         /* The top or left edge position of this child equals the
+            bottom or right edge of its predecessor.  */
+         if (width_p)
+           c->left = make_number (last_pos);
+         else
+           c->top = make_number (last_pos);
 
-         /* Now advance child to next window,
-            and set lastright if child was not just deleted.  */
-         lastright = pos + left, lastoright = opos;
+         /* If this child can be resized, do it.  */
+         if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
+           {
+             new_size = old_size + each + extra;
+             extra = 0;
+           }
+         
+         /* 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);
+
+         /* 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;
        }
-      /* Delete children that became too small */
-      if (!nodelete)
-       for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+
+      /* We should have covered the parent exactly with child windows.  */
+      xassert (size == last_pos - first_pos);
+      
+      /* Now delete any children that became too small.  */
+      if (!nodelete_p)
+       for (child = *forward; !NILP (child); child = c->next)
          {
-           set_window_width (child, XINT (XWINDOW (child)->width), 0);
+           int child_size;
+           c = XWINDOW (child);
+           child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+           size_window (child, child_size, width_p, 0);
          }
     }
 }
-\f
-int window_select_count;
 
-Lisp_Object
-Fset_window_buffer_unwind (obuf)
-     Lisp_Object obuf;
-{
-  Fset_buffer (obuf);
-  return Qnil;
+/* Set WINDOW's height to HEIGHT, and recursively change the height of
+   WINDOW's children.  NODELETE non-zero means don't delete windows
+   that become too small in the process.  (The caller should check
+   later and do so if appropriate.)  */
+
+void
+set_window_height (window, height, nodelete)
+     Lisp_Object window;
+     int height;
+     int nodelete;
+{
+  size_window (window, height, 0, nodelete);
 }
 
-DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
-  "Make WINDOW display BUFFER as its contents.\n\
-BUFFER can be a buffer or buffer name.")
-  (window, buffer)
-     register Lisp_Object window, buffer;
+
+/* Set WINDOW's width to WIDTH, and recursively change the width of
+   WINDOW's children.  NODELETE non-zero means don't delete windows
+   that become too small in the process.  (The caller should check
+   later and do so if appropriate.)  */
+
+void
+set_window_width (window, width, nodelete)
+     Lisp_Object window;
+     int width;
+     int nodelete;
 {
-  register Lisp_Object tem;
-  register struct window *w = decode_window (window);
-  int count = specpdl_ptr - specpdl;
+  size_window (window, width, 1, nodelete);
+}
 
-  buffer = Fget_buffer (buffer);
-  CHECK_BUFFER (buffer, 1);
+\f
+int window_select_count;
 
-  if (NILP (XBUFFER (buffer)->name))
-    error ("Attempt to display deleted buffer");
+Lisp_Object
+Fset_window_buffer_unwind (obuf)
+     Lisp_Object obuf;
+{
+  Fset_buffer (obuf);
+  return Qnil;
+}
 
-  tem = w->buffer;
-  if (NILP (tem))
-    error ("Window is deleted");
-  else if (! EQ (tem, Qt))     /* w->buffer is t when the window
-                                  is first being set up.  */
-    {
-      if (!NILP (w->dedicated) && !EQ (tem, buffer))
-       error ("Window is dedicated to `%s'",
-              XSTRING (XBUFFER (tem)->name)->data);
 
-      unshow_buffer (w);
-    }
+/* 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.  */
+
+void
+set_window_buffer (window, buffer, run_hooks_p)
+     Lisp_Object window, buffer;
+     int run_hooks_p;
+{
+  struct window *w = XWINDOW (window);
+  struct buffer *b = XBUFFER (buffer);
+  int count = specpdl_ptr - specpdl;
 
   w->buffer = buffer;
 
   if (EQ (window, selected_window))
-    XBUFFER (w->buffer)->last_selected_window = window;
+    b->last_selected_window = window;
+
+  /* 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 ();
 
   XSETFASTINT (w->window_end_pos, 0);
+  XSETFASTINT (w->window_end_vpos, 0);
+  bzero (&w->last_cursor, sizeof w->last_cursor);
   w->window_end_valid = Qnil;
   XSETFASTINT (w->hscroll, 0);
-  Fset_marker (w->pointm,
-              make_number (BUF_PT (XBUFFER (buffer))),
-              buffer);
+  set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
   set_marker_restricted (w->start,
-                        make_number (XBUFFER (buffer)->last_window_start),
+                        make_number (b->last_window_start),
                         buffer);
   w->start_at_line_beg = Qnil;
   w->force_start = Qnil;
@@ -1881,24 +2406,75 @@ BUFFER can be a buffer or buffer name.")
       Fset_buffer (buffer);
     }
 
-  if (! NILP (Vwindow_scroll_functions))
-    run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                         Fmarker_position (w->start));
+  /* Set left and right marginal area width from buffer.  */
+  Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
+
+  if (run_hooks_p)
+    {
+      if (! NILP (Vwindow_scroll_functions))
+       run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                             Fmarker_position (w->start));
+
+      if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+    }
 
   unbind_to (count, Qnil);
+}
+
 
+DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
+  "Make WINDOW display BUFFER as its contents.\n\
+BUFFER can be a buffer or buffer name.")
+  (window, buffer)
+     register Lisp_Object window, buffer;
+{
+  register Lisp_Object tem;
+  register struct window *w = decode_window (window);
+
+  buffer = Fget_buffer (buffer);
+  CHECK_BUFFER (buffer, 1);
+
+  if (NILP (XBUFFER (buffer)->name))
+    error ("Attempt to display deleted buffer");
+
+  tem = w->buffer;
+  if (NILP (tem))
+    error ("Window is deleted");
+  else if (! EQ (tem, Qt))     /* w->buffer is t when the window
+                                  is first being set up.  */
+    {
+      if (!NILP (w->dedicated) && !EQ (tem, buffer))
+       error ("Window is dedicated to `%s'",
+              XSTRING (XBUFFER (tem)->name)->data);
+
+      unshow_buffer (w);
+    }
+
+  set_window_buffer (window, buffer, 1);
   return Qnil;
 }
 
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
   "Select WINDOW.  Most editing will apply to WINDOW's buffer.\n\
-The main editor command loop selects the buffer of the selected window\n\
-before each command.")
+If WINDOW is not already selected, also make WINDOW's buffer current.\n\
+Note that the main editor command loop\n\
+selects the buffer of the selected window before each command.")
   (window)
      register Lisp_Object window;
+{
+  return select_window_1 (window, 1);
+}
+\f
+static Lisp_Object
+select_window_1 (window, recordflag)
+     register Lisp_Object window;
+     int recordflag;
 {
   register struct window *w;
   register struct window *ow = XWINDOW (selected_window);
+  struct frame *sf;
 
   CHECK_LIVE_WINDOW (window, 0);
 
@@ -1911,11 +2487,14 @@ before each command.")
   if (EQ (window, selected_window))
     return window;
 
-  Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
-              ow->buffer);
+  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 (XFRAME (WINDOW_FRAME (w)) != selected_frame)
+  sf = SELECTED_FRAME ();
+  if (XFRAME (WINDOW_FRAME (w)) != sf)
     {
       XFRAME (WINDOW_FRAME (w))->selected_window = window;
       /* Use this rather than Fhandle_switch_frame
@@ -1925,9 +2504,10 @@ before each command.")
       Fselect_frame (WINDOW_FRAME (w), Qnil);
     }
   else
-    selected_frame->selected_window = window;
+    sf->selected_window = window;
 
-  record_buffer (w->buffer);
+  if (recordflag)
+    record_buffer (w->buffer);
   Fset_buffer (w->buffer);
 
   XBUFFER (w->buffer)->last_selected_window = window;
@@ -1950,7 +2530,7 @@ before each command.")
   windows_or_buffers_changed++;
   return window;
 }
-
+\f
 /* Deiconify the frame containing the window WINDOW,
    unless it is the selected frame;
    then return WINDOW.
@@ -1965,20 +2545,91 @@ static Lisp_Object
 display_buffer_1 (window)
      Lisp_Object window;
 {
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+  Lisp_Object frame = XWINDOW (window)->frame;
+  FRAME_PTR f = XFRAME (frame);
+  
   FRAME_SAMPLE_VISIBILITY (f);
-  if (f != selected_frame)
+  
+  if (!EQ (frame, selected_frame))
     {
       if (FRAME_ICONIFIED_P (f))
-       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
+       Fmake_frame_visible (frame);
       else if (FRAME_VISIBLE_P (f))
-       Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
+       Fraise_frame (frame);
     }
+  
   return window;
 }
 
-DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
-       "bDisplay buffer: \nP",
+DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
+  "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
+The value is actually t if the frame should be called with default frame\n\
+parameters, and a list of frame parameters if they were specified.\n\
+See `special-display-buffer-names', and `special-display-regexps'.")
+  (buffer_name)
+     Lisp_Object buffer_name;
+{
+  Lisp_Object tem;
+
+  CHECK_STRING (buffer_name, 1);
+
+  tem = Fmember (buffer_name, Vspecial_display_buffer_names);
+  if (!NILP (tem))
+    return Qt;
+
+  tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
+  if (!NILP (tem))
+    return XCDR (tem);
+
+  for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
+    {
+      Lisp_Object car = XCAR (tem);
+      if (STRINGP (car)
+         && fast_string_match (car, buffer_name) >= 0)
+       return Qt;
+      else if (CONSP (car)
+              && STRINGP (XCAR (car))
+              && fast_string_match (XCAR (car), buffer_name) >= 0)
+       return XCDR (car);
+    }
+  return Qnil;
+}  
+
+DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
+  "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
+See `same-window-buffer-names' and `same-window-regexps'.")
+  (buffer_name)
+     Lisp_Object buffer_name;
+{
+  Lisp_Object tem;
+
+  CHECK_STRING (buffer_name, 1);
+
+  tem = Fmember (buffer_name, Vsame_window_buffer_names);
+  if (!NILP (tem))
+    return Qt;
+
+  tem = Fassoc (buffer_name, Vsame_window_buffer_names);
+  if (!NILP (tem))
+    return Qt;
+
+  for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
+    {
+      Lisp_Object car = XCAR (tem);
+      if (STRINGP (car)
+         && fast_string_match (car, buffer_name) >= 0)
+       return Qt;
+      else if (CONSP (car)
+              && STRINGP (XCAR (car))
+              && fast_string_match (XCAR (car), buffer_name) >= 0)
+       return Qt;
+    }
+  return Qnil;
+}
+
+   /* Use B so the default is (other-buffer).  */
+DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
+     "BDisplay buffer: \nP",
   "Make BUFFER appear in some window but don't select it.\n\
 BUFFER can be a buffer or a buffer name.\n\
 If BUFFER is shown already in some window, just use that one,\n\
@@ -1989,12 +2640,23 @@ Returns the window displaying BUFFER.\n\
 \n\
 The variables `special-display-buffer-names', `special-display-regexps',\n\
 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
-buffer names are handled.")
-  (buffer, not_this_window)
-     register Lisp_Object buffer, not_this_window;
+buffer names are handled.\n\
+\n\
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is t, search all frames.\n\
+If FRAME is a frame, search only that frame.\n\
+If FRAME is nil, search only the selected frame\n\
+ (actually the last nonminibuffer frame),\n\
+ unless `pop-up-frames' is non-nil,\n\
+ which means search visible and iconified frames.")
+  (buffer, not_this_window, frame)
+     register Lisp_Object buffer, not_this_window, frame;
 {
-  register Lisp_Object window, tem;
+  register Lisp_Object window, tem, swp;
+  struct frame *f;
 
+  swp = Qnil;
   buffer = Fget_buffer (buffer);
   CHECK_BUFFER (buffer, 0);
 
@@ -2009,44 +2671,20 @@ buffer names are handled.")
      in the selected window.  */
   if (NILP (not_this_window))
     {
-      tem = Fmember (XBUFFER (buffer)->name, Vsame_window_buffer_names);
-      if (!NILP (tem))
-       {
-         Fswitch_to_buffer (buffer, Qnil);
-         return display_buffer_1 (selected_window);
-       }
-
-      tem = Fassoc (XBUFFER (buffer)->name, Vsame_window_buffer_names);
-      if (!NILP (tem))
+      swp = Fsame_window_p (XBUFFER (buffer)->name);
+      if (!NILP (swp) && !no_switch_window (selected_window))
        {
          Fswitch_to_buffer (buffer, Qnil);
          return display_buffer_1 (selected_window);
        }
-
-      for (tem = Vsame_window_regexps; CONSP (tem); tem = XCONS (tem)->cdr)
-       {
-         Lisp_Object car = XCONS (tem)->car;
-         if (STRINGP (car)
-             && fast_string_match (car, XBUFFER (buffer)->name) >= 0)
-           {
-             Fswitch_to_buffer (buffer, Qnil);
-             return display_buffer_1 (selected_window);
-           }
-         else if (CONSP (car)
-                  && STRINGP (XCONS (car)->car)
-                  && fast_string_match (XCONS (car)->car,
-                                        XBUFFER (buffer)->name) >= 0)
-           {
-             Fswitch_to_buffer (buffer, Qnil);
-             return display_buffer_1 (selected_window);
-           }
-       }
     }
 
   /* If pop_up_frames,
      look for a window showing BUFFER on any visible or iconified frame.
      Otherwise search only the current frame.  */
-  if (pop_up_frames || last_nonminibuf_frame == 0)
+  if (! NILP (frame))
+    tem = frame;
+  else if (pop_up_frames || last_nonminibuf_frame == 0)
     XSETFASTINT (tem, 0);
   else
     XSETFRAME (tem, last_nonminibuf_frame);
@@ -2058,30 +2696,13 @@ buffer names are handled.")
     }
 
   /* Certain buffer names get special handling.  */
-  if (! NILP (Vspecial_display_function))
+  if (!NILP (Vspecial_display_function) && NILP (swp))
     {
-      tem = Fmember (XBUFFER (buffer)->name, Vspecial_display_buffer_names);
-      if (!NILP (tem))
+      tem = Fspecial_display_p (XBUFFER (buffer)->name);
+      if (EQ (tem, Qt))
        return call1 (Vspecial_display_function, buffer);
-
-      tem = Fassoc (XBUFFER (buffer)->name, Vspecial_display_buffer_names);
-      if (!NILP (tem))
-       return call2 (Vspecial_display_function, buffer, XCONS (tem)->cdr);
-
-      for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCONS (tem)->cdr)
-       {
-         Lisp_Object car = XCONS (tem)->car;
-         if (STRINGP (car)
-             && fast_string_match (car, XBUFFER (buffer)->name) >= 0)
-           return call1 (Vspecial_display_function, buffer);
-         else if (CONSP (car)
-                  && STRINGP (XCONS (car)->car)
-                  && fast_string_match (XCONS (car)->car,
-                                        XBUFFER (buffer)->name) >= 0)
-           return call2 (Vspecial_display_function,
-                         buffer,
-                         XCONS (car)->cdr);
-       }
+      if (CONSP (tem))
+       return call2 (Vspecial_display_function, buffer, tem);
     }
 
   /* If there are no frames open that have more than a minibuffer,
@@ -2093,17 +2714,17 @@ buffer names are handled.")
       return display_buffer_1 (window);
     }
 
+  f = SELECTED_FRAME ();
   if (pop_up_windows
-      || FRAME_MINIBUF_ONLY_P (selected_frame)
+      || FRAME_MINIBUF_ONLY_P (f)
       /* If the current frame is a special display frame,
         don't try to reuse its windows.  */
-      || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
-      )
+      || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
     {
       Lisp_Object frames;
 
       frames = Qnil;
-      if (FRAME_MINIBUF_ONLY_P (selected_frame))
+      if (FRAME_MINIBUF_ONLY_P (f))
        XSETFRAME (frames, last_nonminibuf_frame);
       /* Don't try to create a window if would get an error */
       if (split_height_threshold < window_min_height << 1)
@@ -2115,8 +2736,7 @@ buffer names are handled.")
 
       /* If the frame we would try to split cannot be split,
         try other frames.  */
-      if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
-                           : last_nonminibuf_frame))
+      if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
        {
          /* Try visible frames first.  */
          window = Fget_largest_window (Qvisible);
@@ -2134,8 +2754,7 @@ buffer names are handled.")
       if (!NILP (window)
          && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
          && window_height (window) >= split_height_threshold
-         && (XFASTINT (XWINDOW (window)->width)
-             == FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (window))))))
+         && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
        window = Fsplit_window (window, Qnil, Qnil);
       else
        {
@@ -2151,13 +2770,20 @@ buffer names are handled.")
              && window_height (window) >= window_min_height << 1)
            window = Fsplit_window (window, Qnil, 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);
          /* 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.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, Qt);
          if (NILP (window))
            window = Fget_largest_window (Qt);
          /* As a last resort, make a new frame.  */
@@ -2172,16 +2798,15 @@ buffer names are handled.")
            other = lower = XWINDOW (window)->next, upper = window;
          if (!NILP (other)
              /* Check that OTHER and WINDOW are vertically arrayed.  */
-             && XWINDOW (other)->top != XWINDOW (window)->top
-             && XWINDOW (other)->height > XWINDOW (window)->height)
+             && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
+             && (XFASTINT (XWINDOW (other)->height)
+                 > XFASTINT (XWINDOW (window)->height)))
            {
-             int total = XWINDOW (other)->height + XWINDOW (window)->height;
-             Lisp_Object old_selected_window;
-             old_selected_window = selected_window;
-
-             selected_window = upper;
-             change_window_height (total / 2 - XWINDOW (upper)->height, 0);
-             selected_window = old_selected_window;
+             int total = (XFASTINT (XWINDOW (other)->height)
+                          + XFASTINT (XWINDOW (window)->height));
+             enlarge_window (upper,
+                             total / 2 - XFASTINT (XWINDOW (upper)->height),
+                             0);
            }
        }
     }
@@ -2200,29 +2825,32 @@ temp_output_buffer_show (buf)
   register Lisp_Object window;
   register struct window *w;
 
+  XBUFFER (buf)->directory = current_buffer->directory;
+
   Fset_buffer (buf);
   BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
   BEGV = BEG;
   ZV = Z;
   SET_PT (BEG);
-  XBUFFER (buf)->clip_changed = 1;
+  XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
   set_buffer_internal (old);
 
   if (!EQ (Vtemp_buffer_show_function, Qnil))
     call1 (Vtemp_buffer_show_function, buf);
   else
     {
-      window = Fdisplay_buffer (buf, Qnil);
+      window = Fdisplay_buffer (buf, Qnil, Qnil);
 
-      if (XFRAME (XWINDOW (window)->frame) != selected_frame)
+      if (!EQ (XWINDOW (window)->frame, selected_frame))
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
       Vminibuf_scroll_window = window;
       w = XWINDOW (window);
       XSETFASTINT (w->hscroll, 0);
-      set_marker_restricted (w->start, make_number (1), buf);
-      set_marker_restricted (w->pointm, make_number (1), buf);
+      set_marker_restricted_both (w->start, buf, 1, 1);
+      set_marker_restricted_both (w->pointm, buf, 1, 1);
 
-      /* Run temp-buffer-show-hook, with the chosen window selected.  */
+      /* Run temp-buffer-show-hook, with the chosen window selected
+        and it sbuffer current.  */
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object tem;
@@ -2233,13 +2861,15 @@ temp_output_buffer_show (buf)
              if (!NILP (tem))
                {
                  int count = specpdl_ptr - specpdl;
+                 Lisp_Object prev_window;
+                 prev_window = selected_window;
 
                  /* Select the window that was chosen, for running the hook.  */
-                 record_unwind_protect (Fset_window_configuration,
-                                        Fcurrent_window_configuration (Qnil));
-
-                 Fselect_window (window);
+                 record_unwind_protect (Fselect_window, prev_window);
+                 select_window_1 (window, 0);
+                 Fset_buffer (w->buffer);
                  call1 (Vrun_hooks, Qtemp_buffer_show_hook);
+                 select_window_1 (prev_window, 0);
                  unbind_to (count, Qnil);
                }
            }
@@ -2247,7 +2877,7 @@ temp_output_buffer_show (buf)
     }
 }
 \f
-static
+static void
 make_dummy_parent (window)
      Lisp_Object window;
 {
@@ -2284,7 +2914,8 @@ DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
   "Split WINDOW, putting SIZE lines in the first of the pair.\n\
 WINDOW defaults to selected one and SIZE to half its size.\n\
 If optional third arg HORFLAG is non-nil, split side by side\n\
-and put SIZE columns in the first of the pair.")
+and put SIZE columns in the first of the pair.  In that case,\n\
+SIZE includes that window's scroll bar, or the divider column to its right.")
   (window, size, horflag)
      Lisp_Object window, size, horflag;
 {
@@ -2305,8 +2936,10 @@ and put SIZE columns in the first of the pair.")
     {
       if (!NILP (horflag))
        /* Calculate the size of the left-hand window, by dividing
-          the usable space in columns by two. */
-       size_int = XFASTINT (o->width) >> 1;
+          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->width) + 1) >> 1;
       else
        size_int = XFASTINT (o->height) >> 1;
     }
@@ -2318,8 +2951,8 @@ and put SIZE columns in the first of the pair.")
 
   if (MINI_WINDOW_P (o))
     error ("Attempt to split minibuffer window");
-  else if (FRAME_NO_SPLIT_P (fo))
-    error ("Attempt to split unsplittable frame");
+  else if (window_fixed_size_p (o, !NILP (horflag), 0))
+    error ("Attempt to split fixed-size window");
 
   check_min_window_sizes ();
 
@@ -2372,8 +3005,8 @@ and put SIZE columns in the first of the pair.")
   o->next = new;
   p->parent = o->parent;
   p->buffer = Qt;
-
-  Fset_window_buffer (new, o->buffer);
+  p->window_end_valid = Qnil;
+  bzero (&p->last_cursor, sizeof p->last_cursor);
 
   /* Apportion the available frame space among the two new windows */
 
@@ -2394,6 +3027,9 @@ and put SIZE columns in the first of the pair.")
       XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
     }
 
+  /* Adjust glyph matrices.  */
+  adjust_glyphs (fo);
+  Fset_window_buffer (new, o->buffer);
   return new;
 }
 \f
@@ -2404,7 +3040,11 @@ From program, optional second arg non-nil means grow sideways ARG columns.")
      register Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg, 0);
-  change_window_height (XINT (arg), !NILP (side));
+  enlarge_window (selected_window, XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
@@ -2415,7 +3055,11 @@ From program, optional second arg non-nil means shrink sideways arg columns.")
      register Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg, 0);
-  change_window_height (-XINT (arg), !NILP (side));
+  enlarge_window (selected_window, -XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
@@ -2435,50 +3079,58 @@ window_width (window)
   return XFASTINT (p->width);
 }
 
-#define MINSIZE(w)                                             \
-  (widthflag                                                   \
-   ? window_min_width                                          \
-   : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
-
+       
 #define CURBEG(w) \
   *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
 
 #define CURSIZE(w) \
   *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
 
-/* Unlike set_window_height, this function
-   also changes the heights of the siblings so as to
-   keep everything consistent. */
 
-change_window_height (delta, widthflag)
-     register int delta;
-     int widthflag;
-{
-  register Lisp_Object parent;
-  Lisp_Object window;
-  register struct window *p;
-  int *sizep;
-  int (*sizefun) () = widthflag ? window_width : window_height;
-  register int (*setsizefun) () = (widthflag
-                                  ? set_window_width
-                                  : set_window_height);
+/* Enlarge selected_window by DELTA.  WIDTHFLAG non-zero means
+   increase its width.  Siblings of the selected window are resized to
+   fullfil the size request.  If they become too small in the process,
+   they will be deleted.  */
 
+static void
+enlarge_window (window, delta, widthflag)
+     Lisp_Object window;
+     int delta, widthflag;
+{
+  Lisp_Object parent, next, prev;
+  struct window *p;
+  int *sizep, maximum;
+  int (*sizefun) P_ ((Lisp_Object))
+    = widthflag ? window_width : window_height;
+  void (*setsizefun) P_ ((Lisp_Object, int, int))
+    = (widthflag ? set_window_width : set_window_height);
+
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
   check_min_window_sizes ();
 
-  window = selected_window;
+  /* Give up if this window cannot be resized.  */
+  if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
+    error ("Window is not resizable");
+
+  /* Find the parent of the selected window.  */
   while (1)
     {
       p = XWINDOW (window);
       parent = p->parent;
+      
       if (NILP (parent))
        {
          if (widthflag)
            error ("No other window to side of this one");
          break;
        }
-      if (widthflag ? !NILP (XWINDOW (parent)->hchild)
+      
+      if (widthflag
+         ? !NILP (XWINDOW (parent)->hchild)
          : !NILP (XWINDOW (parent)->vchild))
        break;
+      
       window = parent;
     }
 
@@ -2488,8 +3140,12 @@ change_window_height (delta, widthflag)
     register int maxdelta;
 
     maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
-               : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
-               : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
+               : !NILP (p->next) ? ((*sizefun) (p->next)
+                                    - window_min_size (XWINDOW (p->next),
+                                                       widthflag, 0, 0))
+               : !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));
@@ -2501,31 +3157,97 @@ change_window_height (delta, widthflag)
       delta = maxdelta;
   }
 
-  if (*sizep + delta < MINSIZE (window))
+  if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
   if (delta == 0)
     return;
 
-  if (!NILP (p->next)
-      && (*sizefun) (p->next) - delta >= MINSIZE (p->next))
-    {
-      (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
-      (*setsizefun) (window, *sizep + delta, 0);
-      CURBEG (p->next) += delta;
-      /* This does not change size of p->next,
-        but it propagates the new top edge to its children */
-      (*setsizefun) (p->next, (*sizefun) (p->next), 0);
-    }
-  else if (!NILP (p->prev)
-          && (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
+  /* Find the total we can get from other siblings.  */
+  maximum = 0;
+  for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
+    maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
+                                                   widthflag, 0, 0);
+  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+                                                   widthflag, 0, 0);
+
+  /* If we can get it all from them, do so.  */
+  if (delta <= maximum)
     {
-      (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
-      CURBEG (window) -= delta;
-      (*setsizefun) (window, *sizep + delta, 0);
+      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),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+                 
+                 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
+                 (*setsizefun) (window, *sizep + this_one, 0);
+
+                 delta -= this_one;
+               }
+             
+             next = XWINDOW (next)->next;
+           }
+         
+         if (delta == 0)
+           break;
+         
+         if (! NILP (prev))
+           {
+             int this_one = ((*sizefun) (prev)
+                             - window_min_size (XWINDOW (prev),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+                 
+                 first_affected = prev;
+                 
+                 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
+                 (*setsizefun) (window, *sizep + this_one, 0);
+
+                 delta -= this_one;
+               }
+             
+             prev = XWINDOW (prev)->prev;
+           }
+       }
+
+      xassert (delta == 0);
+
+      /* 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)
+       {
+         CURBEG (next) = 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);
+       }
     }
   else
     {
@@ -2537,12 +3259,49 @@ change_window_height (delta, widthflag)
         all the siblings end up with less than one line and are deleted.  */
       if (opht <= *sizep + delta)
        delta1 = opht * opht * 2;
-      /* 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.  */
       else
-       delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
+       {
+         /* 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 rquals the number of resizable
+            children of this window + 1 because we know window itself
+            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))
+             ++n;
+         for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
+           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+             ++n;
+
+         delta1 = n * delta;
+       }
 
       /* Add delta1 lines or columns to this window, and to the parent,
         keeping things consistent while not affecting siblings.  */
@@ -2559,12 +3318,271 @@ change_window_height (delta, widthflag)
 
   XSETFASTINT (p->last_modified, 0);
   XSETFASTINT (p->last_overlay_modified, 0);
+
+  /* Adjust glyph matrices. */
+  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
 }
-#undef MINSIZE
+
 #undef CURBEG
 #undef CURSIZE
 
+
+\f
+/***********************************************************************
+                       Resizing Mini-Windows
+ ***********************************************************************/
+
+static void shrink_window_lowest_first P_ ((struct window *, int));
+
+enum save_restore_action
+{
+    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.  */
+
+static void
+shrink_window_lowest_first (w, height)
+     struct window *w;
+     int height;
+{
+  struct window *c;
+  Lisp_Object child;
+  int old_height;
+
+  xassert (!MINI_WINDOW_P (w));
+
+  /* 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;
+
+  old_height = XFASTINT (w->height);
+  XSETFASTINT (w->height, height);
+
+  if (!NILP (w->hchild))
+    {
+      for (child = w->hchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top = w->top;
+         shrink_window_lowest_first (c, height);
+       }
+    }
+  else if (!NILP (w->vchild))
+    {
+      Lisp_Object last_child;
+      int delta = old_height - height;
+      int last_top;
+      
+      /* 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; !NILP (child); child = XWINDOW (child)->next)
+       last_child = child;
+
+      /* Assign new heights.  We leave only MIN_SAFE_WINDOW_HEIGHT.  */
+      for (child = last_child; delta && !NILP (child); child = c->prev)
+       {
+         int this_one;
+         
+         c = XWINDOW (child);
+         this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
+
+         if (this_one > delta)
+           this_one = delta;
+
+         shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
+         delta -= this_one;
+       }
+
+      /* Compute new positions.  */
+      last_top = w->top;
+      for (child = w->vchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top = make_number (last_top);
+         shrink_window_lowest_first (c, XFASTINT (c->height));
+         last_top += XFASTINT (c->height);
+       }
+    }
+}
+
+
+/* Save, restore, or check positions and sizes in the window tree
+   rooted at W.  ACTION says what to do.
+
+   If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
+   members are valid for all windows in the window tree.  Value is
+   non-zero if they are valid.
+   
+   If ACTION is SAVE_ORIG_SIZES, save members top and height in
+   orig_top and orig_height for all windows in the tree.
+
+   If ACTION is RESTORE_ORIG_SIZES, restore top and height from
+   values stored in orig_top and orig_height for all windows.  */
+
+static int
+save_restore_orig_size (w, action)
+     struct window *w;
+     enum save_restore_action action;
+{
+  int success_p = 1;
+
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       {
+         if (!save_restore_orig_size (XWINDOW (w->hchild), action))
+           success_p = 0;
+       }
+      else if (!NILP (w->vchild))
+       {
+         if (!save_restore_orig_size (XWINDOW (w->vchild), action))
+           success_p = 0;
+       }
+      
+      switch (action)
+       {
+       case CHECK_ORIG_SIZES:
+         if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
+           return 0;
+         break;
+
+       case SAVE_ORIG_SIZES:
+         w->orig_top = w->top;
+         w->orig_height = w->height;
+          XSETFASTINT (w->last_modified, 0);
+          XSETFASTINT (w->last_overlay_modified, 0);
+         break;
+
+       case RESTORE_ORIG_SIZES:
+         xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
+         w->top = w->orig_top;
+         w->height = w->orig_height;
+         w->orig_height = w->orig_top = Qnil;
+          XSETFASTINT (w->last_modified, 0);
+          XSETFASTINT (w->last_overlay_modified, 0);
+         break;
+
+       default:
+         abort ();
+       }
+
+      w = NILP (w->next) ? NULL : XWINDOW (w->next);
+    }
+
+  return success_p;
+}
+
+
+/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
+   without deleting other windows.  */
+
+void
+grow_mini_window (w, delta)
+     struct window *w;
+     int delta;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct window *root;
+  
+  xassert (MINI_WINDOW_P (w));
+  xassert (delta >= 0);
+          
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
+  check_min_window_sizes ();
+
+  /* Compute how much we can enlarge the mini-window without deleting
+     other windows.  */
+  root = XWINDOW (FRAME_ROOT_WINDOW (f));
+  if (delta)
+    {
+      int min_height = window_min_size (root, 0, 0, 0);
+      if (XFASTINT (root->height) - delta < min_height)
+       delta = XFASTINT (root->height) - min_height;
+    }
+    
+  if (delta)
+    {
+      /* 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);
+
+      /* Shrink other windows.  */
+      shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
+
+      /* Grow the mini-window.  */
+      w->top = make_number (XFASTINT (root->top) + XFASTINT (root)->height);
+      w->height = make_number (XFASTINT (w->height) + delta);
+      XSETFASTINT (w->last_modified, 0);
+      XSETFASTINT (w->last_overlay_modified, 0);
+      
+      adjust_glyphs (f);
+    }
+}
+
+
+/* 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.  */
+
+void
+shrink_mini_window (w)
+     struct window *w;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
+
+  if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
+    {
+      save_restore_orig_size (root, RESTORE_ORIG_SIZES);
+      adjust_glyphs (f);
+      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+      windows_or_buffers_changed = 1;
+    }
+  else if (XFASTINT (w->height) > 1)
+    {
+      Lisp_Object window;
+      XSETWINDOW (window, w);
+      enlarge_window (window, 1 - XFASTINT (w->height), 0);
+    }
+}
+
+
 \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
+   xterm.c, e.g. when a frame is cleared and thereby all cursors on
+   the frame are cleared.  */
+
+void
+mark_window_cursors_off (w)
+     struct window *w;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       mark_window_cursors_off (XWINDOW (w->hchild));
+      else if (!NILP (w->vchild))
+       mark_window_cursors_off (XWINDOW (w->vchild));
+      else
+       w->phys_cursor_on_p = 0;
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
+
+
 /* Return number of lines of text (not counting mode line) in W.  */
 
 int
@@ -2585,54 +3603,226 @@ window_internal_height (w)
 }
 
 
-/* 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_internal_width (w)
-     struct window *w;
-{
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
-  int left = XINT (w->left);
-  int width = XINT (w->width);
+/* 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_internal_width (w)
+     struct window *w;
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int width = XINT (w->width);
+
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+    /* Scroll bars occupy a few columns.  */
+    width -= FRAME_SCROLL_BAR_COLS (f);
+  else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+    /* The column of `|' characters separating side-by-side windows
+       occupies one column only.  */
+    width -= 1;
+
+  /* On window-systems, areas to the left and right of the window
+     are used to display bitmaps there.  */
+  if (FRAME_WINDOW_P (f))
+    width -= FRAME_FLAGS_AREA_COLS (f);
+
+  return width;
+}
+
+\f
+/************************************************************************
+                          Window Scrolling
+ ***********************************************************************/
+
+/* Scroll contents of window WINDOW up.  If WHOLE is non-zero, scroll
+   one screen-full, which is defined as the height of the window minus
+   next_screen_context_lines.  If WHOLE is zero, scroll up N lines
+   instead.  Negative values of N mean scroll down.  NOERROR non-zero
+   means don't signal an error if we try to move over BEGV or ZV,
+   respectively.  */
+
+static void
+window_scroll (window, n, whole, noerror)
+     Lisp_Object window;
+     int n;
+     int whole;
+     int noerror;
+{
+  /* If we must, use the pixel-based version which is much slower than
+     the line-based one but can handle varying line heights.  */
+  if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
+    window_scroll_pixel_based (window, n, whole, noerror);
+  else
+    window_scroll_line_based (window, n, whole, noerror);
+}
+
+
+/* Implementation of window_scroll that works based on pixel line
+   heights.  See the comment of window_scroll for parameter
+   descriptions.  */
+
+static void
+window_scroll_pixel_based (window, n, whole, noerror)
+     Lisp_Object window;
+     int n;
+     int whole;
+     int noerror;
+{
+  struct it it;
+  struct window *w = XWINDOW (window);
+  struct text_pos start;
+  Lisp_Object tem;
+  int this_scroll_margin;
+  int preserve_y;
+
+  SET_TEXT_POS_FROM_MARKER (start, w->start);
+  
+  /* If PT is not visible in WINDOW, move back one half of
+     the screen.  */
+  XSETFASTINT (tem, PT);
+  tem = Fpos_visible_in_window_p (tem, window);
+  if (NILP (tem))
+    {
+      /* 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.  */
+      init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+      it.current_y = it.last_visible_y;
+      move_it_vertically (&it, -it.last_visible_y / 2);
+      
+      /* The function move_iterator_vertically may move over more than
+        the specified y-distance.  If it->w is small, e.g. a
+        mini-buffer window, we may end up in front of the window's
+        display area.  This is the case when Start displaying at the
+        start of the line containing PT in this case.  */
+      if (it.current_y <= 0)
+       {
+         init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+         move_it_vertically (&it, 0);
+         it.current_y = 0;
+       }
+
+      start = it.current.pos;
+    }
+
+  /* If scroll_preserve_screen_position is non-zero, we try to set
+     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;
+    }
+  else
+    preserve_y = -1;
 
-  /* If this window is flush against the right edge of the frame, its
-     internal width is its full width.  */
-  if (left + width >= FRAME_WIDTH (f))
-    return width;
+  /* Move iterator it from start the specified distance forward or
+     backward.  The result is the new window start.  */
+  start_display (&it, w, start);
+  if (whole)
+    {
+      int screen_full = (it.last_visible_y
+                        - next_screen_context_lines * CANON_Y_UNIT (it.f));
+      int direction = n < 0 ? -1 : 1;
+      move_it_vertically (&it, direction * screen_full);
+    }
+  else
+    move_it_by_lines (&it, n, 1);
 
-  /* If we are not flush right, then our rightmost columns are
-     occupied by some sort of separator.  */
+  /* End if we end up at ZV or BEGV.  */
+  if ((n > 0 && IT_CHARPOS (it) == ZV)
+      || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
+    {
+      if (noerror)
+       return;
+      else if (IT_CHARPOS (it) == ZV)
+       Fsignal (Qend_of_buffer, Qnil);
+      else
+       Fsignal (Qbeginning_of_buffer, Qnil);
+    }
 
-  /* Scroll bars occupy a few columns.  */
-  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
-    return width - FRAME_SCROLL_BAR_COLS (f);
+  /* Set the window start, and set up the window for redisplay.  */
+  set_marker_restricted (w->start, make_number (IT_CHARPOS (it)), w->buffer);
+  w->start_at_line_beg = Fbolp ();
+  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;
+  
+  it.current_y = it.vpos = 0;
+  
+  /* Preserve the screen position if we must.  */
+  if (preserve_y >= 0)
+    {
+      move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+      SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+    }
+  else
+    {
+      /* Move PT out of scroll margins.  */
+      this_scroll_margin = max (0, scroll_margin);
+      this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
+      this_scroll_margin *= CANON_Y_UNIT (it.f);
 
-  /* The column of `|' characters separating side-by-side windows
-     occupies one column only.  */
-  return width - 1;
+      if (n > 0)
+       {
+         /* 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);
+         while (it.current_y < this_scroll_margin)
+           move_it_by_lines (&it, 1, 1);
+         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+       }
+      else if (n < 0)
+       {
+         /* 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,
+                     MOVE_TO_POS | MOVE_TO_Y);
+      
+         /* Don't put point on a partially visible line at the end.  */
+         if (it.current_y + it.max_ascent + it.max_descent
+             > it.last_visible_y)
+           move_it_by_lines (&it, -1, 0);
+      
+         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+       }
+    }
 }
 
 
-/* Scroll contents of window WINDOW up N lines.  */
+/* Implementation of window_scroll that works based on screen lines.
+   See the comment of window_scroll for parameter descriptions.  */
 
-void
-window_scroll (window, n, noerror)
+static void
+window_scroll_line_based (window, n, whole, noerror)
      Lisp_Object window;
      int n;
+     int whole;
      int noerror;
 {
   register struct window *w = XWINDOW (window);
-  register int opoint = PT;
-  register int pos;
+  register int opoint = PT, opoint_byte = PT_BYTE;
+  register int pos, pos_byte;
   register int ht = window_internal_height (w);
   register Lisp_Object tem;
   int lose;
-  Lisp_Object bolp, nmoved;
+  Lisp_Object bolp;
+  int startpos;
+  struct position posit;
+  int original_vpos;
 
-  /* Always set force_start so that redisplay_window will run
-     the window-scroll-functions.  */
-  w->force_start = Qt;
+  startpos = marker_position (w->start);
+
+  posit = *compute_motion (startpos, 0, 0, 0,
+                          PT, ht, 0,
+                          window_internal_width (w), XINT (w->hscroll),
+                          0, w);
+  original_vpos = posit.vpos;
 
   XSETFASTINT (tem, PT);
   tem = Fpos_visible_in_window_p (tem, window);
@@ -2640,16 +3830,16 @@ window_scroll (window, n, noerror)
   if (NILP (tem))
     {
       Fvertical_motion (make_number (- (ht / 2)), window);
-      XSETFASTINT (tem, PT);
-      Fset_marker (w->start, tem, w->buffer);
+      startpos = PT;
     }
 
-  SET_PT (marker_position (w->start));
+  SET_PT (startpos);
   lose = n < 0 && PT == BEGV;
   Fvertical_motion (make_number (n), window);
   pos = PT;
+  pos_byte = PT_BYTE;
   bolp = Fbolp ();
-  SET_PT (opoint);
+  SET_PT_BOTH (opoint, opoint_byte);
 
   if (lose)
     {
@@ -2661,21 +3851,79 @@ window_scroll (window, n, noerror)
 
   if (pos < ZV)
     {
-      set_marker_restricted (w->start, make_number (pos), w->buffer);
+      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->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
+      set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
       w->start_at_line_beg = bolp;
       w->update_mode_line = Qt;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
-      if (pos > opoint)
-       SET_PT (pos);
-      if (n < 0)
+      /* Set force_start so that redisplay_window will run
+        the window-scroll-functions.  */
+      w->force_start = Qt;
+
+      if (whole && !NILP (Vscroll_preserve_screen_position))
+       {
+         SET_PT_BOTH (pos, pos_byte);
+         Fvertical_motion (make_number (original_vpos), window);
+       }
+      /* If we scrolled forward, put point enough lines down
+        that it is outside the scroll margin.  */
+      else if (n > 0)
+       {
+         int top_margin;
+
+         if (this_scroll_margin > 0)
+           {
+             SET_PT_BOTH (pos, pos_byte);
+             Fvertical_motion (make_number (this_scroll_margin), window);
+             top_margin = PT;
+           }
+         else
+           top_margin = pos;
+
+         if (top_margin <= opoint)
+           SET_PT_BOTH (opoint, opoint_byte);
+         else if (!NILP (Vscroll_preserve_screen_position))
+           {
+             SET_PT_BOTH (pos, pos_byte);
+             Fvertical_motion (make_number (original_vpos), window);
+           }
+         else
+           SET_PT (top_margin);
+       }
+      else if (n < 0)
        {
-         SET_PT (pos);
-         tem = Fvertical_motion (make_number (ht), window);
-         if (PT > opoint || XFASTINT (tem) < ht)
-           SET_PT (opoint);
+         int bottom_margin;
+
+         /* If we scrolled backward, put point near the end of the window
+            but not within the scroll margin.  */
+         SET_PT_BOTH (pos, pos_byte);
+         tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
+         if (XFASTINT (tem) == ht - this_scroll_margin)
+           bottom_margin = PT;
+         else
+           bottom_margin = PT + 1;
+
+         if (bottom_margin > opoint)
+           SET_PT_BOTH (opoint, opoint_byte);
          else
-           Fvertical_motion (make_number (-1), window);
+           {
+             if (!NILP (Vscroll_preserve_screen_position))
+               {
+                 SET_PT_BOTH (pos, pos_byte);
+                 Fvertical_motion (make_number (original_vpos), window);
+               }
+             else
+               Fvertical_motion (make_number (-1), window);
+           }
        }
     }
   else
@@ -2686,23 +3934,33 @@ window_scroll (window, n, noerror)
        Fsignal (Qend_of_buffer, Qnil);
     }
 }
-\f
-/* This is the guts of Fscroll_up and Fscroll_down.  */
+
+
+/* Scroll selected_window up or down.  If N is nil, scroll a
+   screen-full which is defined as the height of the window minus
+   next_screen_context_lines.  If N is the symbol `-', scroll.
+   DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
+   up.  This is the guts of Fscroll_up and Fscroll_down.  */
 
 static void
 scroll_command (n, direction)
-     register Lisp_Object n;
+     Lisp_Object n;
      int direction;
 {
   register int defalt;
   int count = specpdl_ptr - specpdl;
 
-  /* If selected window's buffer isn't current, make it current for the moment.
-     But don't screw up if window_scroll gets an error.  */
+  xassert (abs (direction) == 1);
+
+  /* If selected window's buffer isn't current, make it current for
+     the moment.  But don't screw up if window_scroll gets an error.  */
   if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
     {
       record_unwind_protect (save_excursion_restore, save_excursion_save ());
       Fset_buffer (XWINDOW (selected_window)->buffer);
+
+      /* Make redisplay consider other windows than just selected_window.  */
+      ++windows_or_buffers_changed;
     }
 
   defalt = (window_internal_height (XWINDOW (selected_window))
@@ -2710,13 +3968,13 @@ scroll_command (n, direction)
   defalt = direction * (defalt < 1 ? 1 : defalt);
 
   if (NILP (n))
-    window_scroll (selected_window, defalt, 0);
+    window_scroll (selected_window, defalt, 1, 0);
   else if (EQ (n, Qminus))
-    window_scroll (selected_window, - defalt, 0);
+    window_scroll (selected_window, - defalt, 1, 0);
   else
     {
       n = Fprefix_numeric_value (n);
-      window_scroll (selected_window, XINT (n) * direction, 0);
+      window_scroll (selected_window, XINT (n) * direction, 0, 0);
     }
 
   unbind_to (count, Qnil);
@@ -2726,7 +3984,8 @@ DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
   "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2735,10 +3994,11 @@ When calling from a program, supply a number as argument or nil.")
 }
 
 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
-  "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
+  "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll upward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll upward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2764,7 +4024,7 @@ showing that buffer is used.")
     {
       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
       if (NILP (window))
-       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
+       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
     }
   else
     {
@@ -2791,9 +4051,11 @@ showing that buffer is used.")
 
 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
   "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
+A near full screen is `next-screen-context-lines' less than a full screen.\n\
 The next window is the one below the current one; or the one at the top\n\
 if the current one is at the bottom.  Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.\n\
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.\n\
 \n\
 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
 specifies the window to scroll.\n\
@@ -2815,23 +4077,24 @@ showing that buffer, popping the buffer up if necessary.")
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
+  ++windows_or_buffers_changed;
 
   Fset_buffer (w->buffer);
   SET_PT (marker_position (w->pointm));
 
   if (NILP (arg))
-    window_scroll (window, defalt, 1);
+    window_scroll (window, defalt, 1, 1);
   else if (EQ (arg, Qminus))
-    window_scroll (window, -defalt, 1);
+    window_scroll (window, -defalt, 1, 1);
   else
     {
       if (CONSP (arg))
        arg = Fcar (arg);
       CHECK_NUMBER (arg, 0);
-      window_scroll (window, XINT (arg), 1);
+      window_scroll (window, XINT (arg), 0, 1);
     }
 
-  Fset_marker (w->pointm, make_number (PT), Qnil);
+  set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
   unbind_to (count, Qnil);
 
   return Qnil;
@@ -2884,11 +4147,14 @@ redraws with point in the center of the current window.")
   register struct window *w = XWINDOW (selected_window);
   register int ht = window_internal_height (w);
   struct position pos;
+  struct buffer *buf = XBUFFER (w->buffer);
+  struct buffer *obuf = current_buffer;
 
   if (NILP (arg))
     {
       extern int frame_garbaged;
 
+      Fredraw_frame (w->frame);
       SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
       XSETFASTINT (arg, ht / 2);
     }
@@ -2905,13 +4171,15 @@ redraws with point in the center of the current window.")
   if (XINT (arg) < 0)
     XSETINT (arg, XINT (arg) + ht);
 
+  set_buffer_internal (buf);
   pos = *vmotion (PT, - XINT (arg), w);
 
-  Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
-  w->start_at_line_beg = ((pos.bufpos == BEGV
-                          || FETCH_CHAR (pos.bufpos - 1) == '\n')
+  set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+  w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+                          || FETCH_BYTE (pos.bytepos - 1) == '\n')
                          ? Qt : Qnil);
   w->force_start = Qt;
+  set_buffer_internal (obuf);
 
   return Qnil;
 }
@@ -2920,8 +4188,8 @@ DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
   1, 1, "P",
   "Position point relative to window.\n\
 With no argument, position point at center of window.\n\
-An argument specifies frame line; zero means top of window,\n\
-negative means relative to bottom of window.")
+An argument specifies vertical position within the window;\n\
+zero means top of window, negative means relative to bottom of window.")
   (arg)
      register Lisp_Object arg;
 {
@@ -2944,21 +4212,28 @@ negative means relative to bottom of window.")
   if (start < BEGV || start > ZV)
     {
       Fvertical_motion (make_number (- (height / 2)), window);
-      Fset_marker (w->start, make_number (PT), w->buffer);
+      set_marker_both (w->start, w->buffer, PT, PT_BYTE);
       w->start_at_line_beg = Fbolp ();
       w->force_start = Qt;
     }
   else
-    SET_PT (start);
+    Fgoto_char (w->start);
 
   return Fvertical_motion (arg, window);
 }
+
+
 \f
+/***********************************************************************
+                        Window Configuration
+ ***********************************************************************/
+
 struct save_window_data
   {
     EMACS_INT size_from_Lisp_Vector_struct;
     struct Lisp_Vector *next_from_Lisp_Vector_struct;
     Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
+    Lisp_Object frame_tool_bar_lines;
     Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object current_buffer;
@@ -2968,11 +4243,12 @@ struct save_window_data
     /* Record the values of window-min-width and window-min-height
        so that window sizes remain consistent with them.  */
     Lisp_Object min_width, min_height;
-    /* A vector, interpreted as a struct saved_window */
+    /* A vector, each of whose elements is a struct saved_window
+       for one window.  */
     Lisp_Object saved_windows;
   };
 
-/* This is saved as a Lisp_Vector */
+/* This is saved as a Lisp_Vector  */
 struct saved_window
   {
     /* these first two must agree with struct Lisp_Vector in lisp.h */
@@ -2992,7 +4268,7 @@ struct saved_window
   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
 
 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
-  "T if OBJECT is a window-configuration object.")
+  "Return t if OBJECT is a window-configuration object.")
   (object)
      Lisp_Object object;
 {
@@ -3001,13 +4277,31 @@ DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_
   return Qnil;
 }
 
+DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
+  "Return the frame that CONFIG, a window-configuration object, is about.")
+  (config)
+     Lisp_Object config;
+{
+  register struct save_window_data *data;
+  struct Lisp_Vector *saved_windows;
+
+  if (! WINDOW_CONFIGURATIONP (config))
+    wrong_type_argument (Qwindow_configuration_p, config);
+
+  data = (struct save_window_data *) XVECTOR (config);
+  saved_windows = XVECTOR (data->saved_windows);
+  return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
+}
 
 DEFUN ("set-window-configuration", Fset_window_configuration,
   Sset_window_configuration, 1, 1, 0,
   "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
 CONFIGURATION must be a value previously returned\n\
-by `current-window-configuration' (which see).")
-     (configuration)
+by `current-window-configuration' (which see).\n\
+If CONFIGURATION was made from a frame that is now deleted,\n\
+only frame-independent values can be restored.  In this case,\n\
+the return value is nil.  Otherwise the value is t.")
+  (configuration)
      Lisp_Object configuration;
 {
   register struct save_window_data *data;
@@ -3015,12 +4309,10 @@ by `current-window-configuration' (which see).")
   Lisp_Object new_current_buffer;
   Lisp_Object frame;
   FRAME_PTR f;
+  int old_point = -1;
 
   while (!WINDOW_CONFIGURATIONP (configuration))
-    {
-      configuration = wrong_type_argument (intern ("window-configuration-p"),
-                                          configuration);
-    }
+    wrong_type_argument (Qwindow_configuration_p, configuration);
 
   data = (struct save_window_data *) XVECTOR (configuration);
   saved_windows = XVECTOR (data->saved_windows);
@@ -3028,6 +4320,12 @@ by `current-window-configuration' (which see).")
   new_current_buffer = data->current_buffer;
   if (NILP (XBUFFER (new_current_buffer)->name))
     new_current_buffer = Qnil;
+  else
+    {
+      if (XBUFFER (new_current_buffer) == current_buffer)
+       old_point = PT;
+
+    }
 
   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
   f = XFRAME (frame);
@@ -3038,7 +4336,10 @@ by `current-window-configuration' (which see).")
     {
       register struct window *w;
       register struct saved_window *p;
-      int k;
+      struct window *root_window;
+      struct window **leaf_windows;
+      int n_leaf_windows;
+      int k, i;
 
       /* If the frame has been resized since this window configuration was
         made, we change the frame to the size specified in the
@@ -3047,19 +4348,49 @@ by `current-window-configuration' (which see).")
       int previous_frame_height = FRAME_HEIGHT (f);
       int previous_frame_width =  FRAME_WIDTH  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
+      int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+
+      /* The mouse highlighting code could get screwed up
+        if it runs during this.  */
+      BLOCK_INPUT;
 
       if (XFASTINT (data->frame_height) != previous_frame_height
          || XFASTINT (data->frame_width) != previous_frame_width)
-       change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
+       change_frame_size (f, XFASTINT (data->frame_height),
+                          XFASTINT (data->frame_width), 0, 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (XFASTINT (data->frame_menu_bar_lines)
          != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
+#ifdef HAVE_WINDOW_SYSTEM
+      if (XFASTINT (data->frame_tool_bar_lines)
+         != previous_frame_tool_bar_lines)
+       x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
+#endif
 #endif
 
+      if (! NILP (XWINDOW (selected_window)->buffer))
+       {
+         w = XWINDOW (selected_window);
+         set_marker_both (w->pointm,
+                          w->buffer,
+                          BUF_PT (XBUFFER (w->buffer)),
+                          BUF_PT_BYTE (XBUFFER (w->buffer)));
+       }
+
       windows_or_buffers_changed++;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
+      /* Problem: Freeing all matrices and later allocating them again
+        is a serious redisplay flickering problem.  What we would 
+        really like to do is to free only those matrices not reused
+        below.   */
+      root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
+      leaf_windows
+       = (struct window **) alloca (count_windows (root_window)
+                                    * sizeof (struct window *));
+      n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
+
       /* Temporarily avoid any problems with windows that are smaller
         than they are supposed to be.  */
       window_min_height = 1;
@@ -3133,14 +4464,10 @@ by `current-window-configuration' (which see).")
                {
                  w->buffer = p->buffer;
                  w->start_at_line_beg = p->start_at_line_beg;
-                 set_marker_restricted (w->start,
-                                        Fmarker_position (p->start),
-                                        w->buffer);
-                 set_marker_restricted (w->pointm,
-                                        Fmarker_position (p->pointm),
-                                        w->buffer);
+                 set_marker_restricted (w->start, p->start, w->buffer);
+                 set_marker_restricted (w->pointm, p->pointm, w->buffer);
                  Fset_marker (XBUFFER (w->buffer)->mark,
-                              Fmarker_position (p->mark), w->buffer);
+                              p->mark, w->buffer);
 
                  /* As documented in Fcurrent_window_configuration, don't
                     save the location of point in the buffer which was current
@@ -3168,10 +4495,9 @@ by `current-window-configuration' (which see).")
                    set_marker_restricted (w->start, make_number (0),
                                           w->buffer);
                  if (XMARKER (w->pointm)->buffer == 0)
-                   set_marker_restricted (w->pointm,
-                                          (make_number
-                                           (BUF_PT (XBUFFER (w->buffer)))),
-                                          w->buffer);
+                   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;
                }
            }
@@ -3179,6 +4505,8 @@ by `current-window-configuration' (which see).")
 
       FRAME_ROOT_WINDOW (f) = data->root_window;
       Fselect_window (data->current_window);
+      XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
+       = selected_window;
 
       if (NILP (data->focus_frame)
          || (FRAMEP (data->focus_frame)
@@ -3196,30 +4524,64 @@ by `current-window-configuration' (which see).")
       if (previous_frame_height != FRAME_HEIGHT (f)
          || previous_frame_width != FRAME_WIDTH (f))
        change_frame_size (f, previous_frame_height, previous_frame_width,
-                          0, 0);
+                          0, 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
-       x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
+                             make_number (0));
+#ifdef HAVE_WINDOW_SYSTEM
+      if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
+       x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
+                             make_number (0));
+#endif
 #endif
+
+      /* Now, free glyph matrices in windows that were not reused.  */
+      for (i = 0; i < n_leaf_windows; ++i)
+       if (NILP (leaf_windows[i]->buffer))
+         {
+           /* Assert it's not reused as a combination.  */
+           xassert (NILP (leaf_windows[i]->hchild) 
+                    && NILP (leaf_windows[i]->vchild));
+           free_window_matrices (leaf_windows[i]);
+           SET_FRAME_GARBAGED (f);
+         }
+      
+      adjust_glyphs (f);
+
+      UNBLOCK_INPUT;
+
+      /* 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
+        Fselect_window above totally superfluous; it still sets f's
+        selected window.  */
+      if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
+       do_switch_frame (data->selected_frame, Qnil, 0);
+
+      if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+    }
+
+  if (!NILP (new_current_buffer))
+    {
+      Fset_buffer (new_current_buffer);
+
+      /* If the buffer that is current now is the same
+        that was current before setting the window configuration,
+        don't alter its PT.  */
+      if (old_point >= 0)
+       SET_PT (old_point);
     }
 
   /* Restore the minimum heights recorded in the configuration.  */
   window_min_height = XINT (data->min_height);
   window_min_width = XINT (data->min_width);
 
-  /* 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
-     Fselect_window above totally superfluous; it still sets f's
-     selected window.  */
-  if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
-    do_switch_frame (data->selected_frame, Qnil, 0);
-
-  if (!NILP (new_current_buffer))
-    Fset_buffer (new_current_buffer);
-
   Vminibuf_scroll_window = data->minibuf_scroll_window;
-  return (Qnil);
+
+  return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 
 /* Mark all windows now on frame as deleted
@@ -3264,6 +4626,56 @@ count_windows (window)
   return count;
 }
 
+
+/* 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;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
+      else if (!NILP (w->vchild))
+       i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
+      else 
+       flat[i++] = w;
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+
+  return 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
+   can be returned.  */
+
+struct glyph *
+get_phys_cursor_glyph (w)
+     struct window *w;
+{
+  struct glyph_row *row;
+  struct glyph *glyph;
+
+  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;
+  else
+    glyph = NULL;
+
+  return glyph;
+}
+
+
 static int
 save_window_save (window, vector, i)
      Lisp_Object window;
@@ -3296,8 +4708,9 @@ save_window_save (window, vector, i)
          if (EQ (window, selected_window))
            {
              p->pointm = Fmake_marker ();
-             Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
-                          w->buffer);
+             set_marker_both (p->pointm, w->buffer,
+                              BUF_PT (XBUFFER (w->buffer)),
+                              BUF_PT_BYTE (XBUFFER (w->buffer)));
            }
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
@@ -3335,8 +4748,8 @@ save_window_save (window, vector, i)
   return i;
 }
 
-DEFUN ("current-window-configuration",
-       Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0,
+DEFUN ("current-window-configuration", Fcurrent_window_configuration,
+  Scurrent_window_configuration, 0, 1, 0,
   "Return an object representing the current window configuration of FRAME.\n\
 If FRAME is nil or omitted, use the selected frame.\n\
 This describes the number of windows, their sizes and current buffers,\n\
@@ -3356,12 +4769,9 @@ redirection (see `redirect-frame-focus').")
   FRAME_PTR f;
 
   if (NILP (frame))
-    f = selected_frame;
-  else
-    {
-      CHECK_LIVE_FRAME (frame, 0);
-      f = XFRAME (frame);
-    }
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 0);
+  f = XFRAME (frame);
 
   n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
   vec = allocate_vectorlike (VECSIZE (struct save_window_data));
@@ -3373,7 +4783,8 @@ redirection (see `redirect-frame-focus').")
   XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
   XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
   XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
-  XSETFRAME (data->selected_frame, selected_frame);
+  XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
+  data->selected_frame = selected_frame;
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
   data->minibuf_scroll_window = Vminibuf_scroll_window;
@@ -3411,23 +4822,359 @@ Does not restore the value of point in current buffer.")
   val = Fprogn (args);
   return unbind_to (count, val);
 }
+
+\f
+/***********************************************************************
+                           Marginal Areas
+ ***********************************************************************/
+
+DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
+       2, 3, "",
+  "Set width of marginal areas of window WINDOW.\n\
+If window is nil or omitted, set margins of the currently selected window.\n\
+First parameter LEFT-WIDTH specifies the number of character\n\
+cells to reserve for the left marginal area.  Second parameter\n\
+RIGHT-WIDTH does the same for the right marginal area.\n\
+A nil width parameter means no margin.")
+  (window, left, right)
+     Lisp_Object window, left, right;
+{
+  struct window *w = decode_window (window);
+
+  if (!NILP (left))
+    CHECK_NUMBER_OR_FLOAT (left, 1);
+  if (!NILP (right))
+    CHECK_NUMBER_OR_FLOAT (right, 2);
+
+  /* Check widths < 0 and translate a zero width to nil.
+     Margins that are too wide have to be checked elsewhere.  */
+  if ((INTEGERP (left) && XINT (left) < 0)
+      || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
+     XSETFASTINT (left, 0);
+  if (INTEGERP (left) && XFASTINT (left) == 0)
+    left = Qnil;
+  
+  if ((INTEGERP (right) && XINT (right) < 0)
+      || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
+    XSETFASTINT (right, 0);
+  if (INTEGERP (right) && XFASTINT (right) == 0)
+    right = Qnil;
+
+  w->left_margin_width = left;
+  w->right_margin_width = right;
+
+  ++windows_or_buffers_changed;
+  adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+  return Qnil;
+}
+
+
+DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
+       0, 1, 0,
+  "Get width of marginal areas of window WINDOW.\n\
+If WINDOW is omitted or nil, use the currently selected window.\n\
+Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
+If a marginal area does not exist, its width will be returned\n\
+as nil.")
+  (window)
+     Lisp_Object window;
+{
+  struct window *w = decode_window (window);
+  return Fcons (w->left_margin_width, w->right_margin_width);
+}
+
+
+\f
+/***********************************************************************
+                          Smooth scrolling
+ ***********************************************************************/
+
+DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
+  "Return the amount by which WINDOW is scrolled vertically.\n\
+Use the selected window if WINDOW is nil or omitted.\n\
+Value is a multiple of the canonical character height of WINDOW.")
+  (window)
+     Lisp_Object window;
+{
+  Lisp_Object result;
+  struct frame *f;
+  struct window *w;
+  
+  if (NILP (window))
+    window = selected_window;
+  else
+    CHECK_WINDOW (window, 0);
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
+  
+  if (FRAME_WINDOW_P (f))
+    result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
+  else
+    result = make_number (0);
+  return result;
+}
+
+
+DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
+       2, 2, 0,
+  "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
+WINDOW nil or omitted means use the selected window.  VSCROLL is a\n\
+non-negative multiple of the canonical character height of WINDOW.")
+  (window, vscroll)
+     Lisp_Object window, vscroll;
+{
+  struct window *w;
+  struct frame *f;
+  
+  if (NILP (window))
+    window = selected_window;
+  else
+    CHECK_WINDOW (window, 0);
+  CHECK_NUMBER_OR_FLOAT (vscroll, 1);
+  
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
+
+  if (FRAME_WINDOW_P (f))
+    {
+      int old_dy = w->vscroll;
+      
+      w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
+      w->vscroll = min (w->vscroll, 0);
+
+      /* Adjust glyph matrix of the frame if the virtual display
+        area becomes larger than before.  */
+      if (w->vscroll < 0 && w->vscroll < old_dy)
+       adjust_glyphs (f);
+      
+      /* Prevent redisplay shortcuts.  */
+      XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+    }
+  
+  return Fwindow_vscroll (window);
+}
+       
+\f
+/* Call FN for all leaf windows on frame F.  FN is called with the
+   first argument being a pointer to the leaf window, and with
+   additional arguments A1..A4.  */
+
+void
+foreach_window (f, fn, a1, a2, a3, a4)
+     struct frame *f;
+     void (* fn) ();
+     int a1, a2, a3, a4;
+{
+  foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
+}
+
+
+/* Helper function for foreach_window.  Call FN for all leaf windows
+   reachable from W.  FN is called with the first argument being a
+   pointer to the leaf window, and with additional arguments A1..A4.  */
+
+static void
+foreach_window_1 (w, fn, a1, a2, a3, a4)
+     struct window *w;
+     void (* fn) ();
+     int a1, a2, a3, a4;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
+      else if (!NILP (w->vchild))
+       foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
+      else
+       fn (w, a1, a2, a3, a4);
+      
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
+
+
+/* Freeze or unfreeze the window start of W if unless it is a
+   mini-window or the selected window.  FREEZE_P non-zero means freeze
+   the window start.  */
+
+static void
+freeze_window_start (w, freeze_p)
+     struct window *w;
+     int freeze_p;
+{
+  if (w == XWINDOW (selected_window)
+      || MINI_WINDOW_P (w)
+      || (MINI_WINDOW_P (XWINDOW (selected_window))
+         && w == XWINDOW (Vminibuf_scroll_window)))
+    freeze_p = 0;
+  
+  w->frozen_window_start_p = freeze_p;
+}
+
+
+/* Freeze or unfreeze the window starts of all leaf windows on frame
+   F, except the selected window and a mini-window.  FREEZE_P non-zero
+   means freeze the window start.  */
+
+void
+freeze_window_starts (f, freeze_p)
+     struct frame *f;
+     int freeze_p;
+{
+  foreach_window (f, freeze_window_start, freeze_p);
+}
+
+\f
+/***********************************************************************
+                           Initialization
+ ***********************************************************************/
+
+/* Return 1 if window configurations C1 and C2
+   describe the same state of affairs.  This is used by Fequal.   */
+
+int
+compare_window_configurations (c1, c2, ignore_positions)
+     Lisp_Object c1, c2;
+     int ignore_positions;
+{
+  register struct save_window_data *d1, *d2;
+  struct Lisp_Vector *sw1, *sw2;
+  int i;
+
+  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 (! EQ (d1->frame_width, d2->frame_width))
+    return 0;
+  if (! EQ (d1->frame_height, d2->frame_height))
+    return 0;
+  if (! EQ (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;
+  /* 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;
+  if (! EQ (d1->min_width, d2->min_width))
+    return 0;
+  if (! EQ (d1->min_height, d2->min_height))
+    return 0;
+
+  /* Verify that the two confis have the same number of windows.  */
+  if (sw1->size != sw2->size)
+    return 0;
+
+  for (i = 0; i < sw1->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, p2->left))
+       return 0;
+      if (! EQ (p1->top, p2->top))
+       return 0;
+      if (! EQ (p1->width, p2->width))
+       return 0;
+      if (! EQ (p1->height, p2->height))
+       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->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;
+       }
+    }
+
+  return 1;
+}
+
+DEFUN ("compare-window-configurations", Fcompare_window_configurations,
+       Scompare_window_configurations, 2, 2, 0,
+  "Compare two window configurations as regards the structure of windows.\n\
+This function ignores details such as the values of point and mark\n\
+and scrolling positions.")
+  (x, y)
+     Lisp_Object x, y;
+{
+  if (compare_window_configurations (x, y, 1))
+    return Qt;
+  return Qnil;
+}
 \f
+void
 init_window_once ()
 {
-  selected_frame = make_terminal_frame ();
-  XSETFRAME (Vterminal_frame, selected_frame);
-  minibuf_window = selected_frame->minibuffer_window;
-  selected_window = selected_frame->selected_window;
-  last_nonminibuf_frame = selected_frame;
+  struct frame *f = make_terminal_frame ();
+  XSETFRAME (selected_frame, f);
+  Vterminal_frame = selected_frame;
+  minibuf_window = f->minibuffer_window;
+  selected_window = f->selected_window;
+  last_nonminibuf_frame = f;
 
   window_initialized = 1;
 }
 
+void
 syms_of_window ()
 {
+  Qleft_bitmap_area = intern ("left-bitmap-area");
+  staticpro (&Qleft_bitmap_area);
+  Qright_bitmap_area = intern ("right-bitmap-area");
+  staticpro (&Qright_bitmap_area);
+  
+  Qwindow_size_fixed = intern ("window-size-fixed");
+  staticpro (&Qwindow_size_fixed);
+  
+  staticpro (&Qwindow_configuration_change_hook);
+  Qwindow_configuration_change_hook
+    = intern ("window-configuration-change-hook");
+
   Qwindowp = intern ("windowp");
   staticpro (&Qwindowp);
 
+  Qwindow_configuration_p = intern ("window-configuration-p");
+  staticpro (&Qwindow_configuration_p);
+
   Qwindow_live_p = intern ("window-live-p");
   staticpro (&Qwindow_live_p);
 
@@ -3473,14 +5220,20 @@ where `pop-up-frame-alist' would hold the default frame parameters.");
   DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
     "*List of buffer names that should have their own special frames.\n\
 Displaying a buffer whose name is in this list makes a special frame for it\n\
-using `special-display-function'.\n\
+using `special-display-function'.  See also `special-display-regexps'.\n\
 \n\
-An element of the list can be a cons cell instead of just a string.\n\
-Then the car should be a buffer name, and the cdr specifies frame\n\
-parameters for creating the frame for that buffer.\n\
-More precisely, the cdr is passed as the second argument to\n\
-the function found in `special-display-function', when making that frame.\n\
-See also `special-display-regexps'.");
+An element of the list can be a list instead of just a string.\n\
+There are two ways to use a list as an element:\n\
+  (BUFFER FRAME-PARAMETERS...)   (BUFFER FUNCTION OTHER-ARGS...)\n\
+In the first case, FRAME-PARAMETERS are used to create the frame.\n\
+In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
+followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
+All this is done by the function found in `special-display-function'.\n\
+\n\
+If this variable appears \"not to work\", because you add a name to it\n\
+but that buffer still appears in the selected window, look at the\n\
+values of `same-window-buffer-names' and `same-window-regexps'.\n\
+Those variables take precedence over this one.");
   Vspecial_display_buffer_names = Qnil;
 
   DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
@@ -3489,12 +5242,18 @@ If a buffer name matches one of these regexps, it gets its own frame.\n\
 Displaying a buffer whose name is in this list makes a special frame for it\n\
 using `special-display-function'.\n\
 \n\
-An element of the list can be a cons cell instead of just a string.\n\
-Then the car should be the regexp, and the cdr specifies frame\n\
-parameters for creating the frame for buffers that match.\n\
-More precisely, the cdr is passed as the second argument to\n\
-the function found in `special-display-function', when making that frame.\n\
-See also `special-display-buffer-names'.");
+An element of the list can be a list instead of just a string.\n\
+There are two ways to use a list as an element:\n\
+  (REGEXP FRAME-PARAMETERS...)   (REGEXP FUNCTION OTHER-ARGS...)\n\
+In the first case, FRAME-PARAMETERS are used to create the frame.\n\
+In the latter case, FUNCTION is called with the buffer as first argument,\n\
+followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
+All this is done by the function found in `special-display-function'.\n\
+\n\
+If this variable appears \"not to work\", because you add a regexp to it\n\
+but the matching buffers still appear in the selected window, look at the\n\
+values of `same-window-buffer-names' and `same-window-regexps'.\n\
+Those variables take precedence over this one.");
   Vspecial_display_regexps = Qnil;
 
   DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
@@ -3557,6 +5316,17 @@ If there is only one window, it is split regardless of this value.");
     "*Delete any window less than this wide.");
   window_min_width = 10;
 
+  DEFVAR_LISP ("scroll-preserve-screen-position",
+              &Vscroll_preserve_screen_position,
+    "*Nonzero means scroll commands move point to keep its screen line unchanged.");
+  Vscroll_preserve_screen_position = Qnil;
+
+  DEFVAR_LISP ("window-configuration-change-hook",
+              &Vwindow_configuration_change_hook,
+    "Functions to call when window configuration changes.\n\
+The selected frame is the one whose configuration has changed.");
+  Vwindow_configuration_change_hook = Qnil;
+
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);
@@ -3594,6 +5364,8 @@ If there is only one window, it is split regardless of this value.");
   defsubr (&Sdelete_window);
   defsubr (&Sset_window_buffer);
   defsubr (&Sselect_window);
+  defsubr (&Sspecial_display_p);
+  defsubr (&Ssame_window_p);
   defsubr (&Sdisplay_buffer);
   defsubr (&Ssplit_window);
   defsubr (&Senlarge_window);
@@ -3607,11 +5379,18 @@ If there is only one window, it is split regardless of this value.");
   defsubr (&Srecenter);
   defsubr (&Smove_to_window_line);
   defsubr (&Swindow_configuration_p);
+  defsubr (&Swindow_configuration_frame);
   defsubr (&Sset_window_configuration);
   defsubr (&Scurrent_window_configuration);
   defsubr (&Ssave_window_excursion);
+  defsubr (&Sset_window_margins);
+  defsubr (&Swindow_margins);
+  defsubr (&Swindow_vscroll);
+  defsubr (&Sset_window_vscroll);
+  defsubr (&Scompare_window_configurations);
 }
 
+void
 keys_of_window ()
 {
   initial_define_key (control_x_map, '1', "delete-other-windows");