(iso-languages): For Portuguese ~c and
[bpt/emacs.git] / src / window.c
index 56fa588..1198b05 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 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.
 
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include "lisp.h"
@@ -28,14 +29,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "termchar.h"
 #include "disptab.h"
 #include "keyboard.h"
+#include "blockinput.h"
+#include "dispextern.h"
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif
 
-Lisp_Object Qwindowp, Qwindow_live_p;
+Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
 
-Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
-Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
+static struct window *decode_window P_ ((Lisp_Object));
 
-void delete_all_subwindows ();
-static struct window *decode_window();
+static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -97,7 +101,7 @@ 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 
+/* Fdisplay_buffer always splits the largest window
    if that window is more than this high.  */
 int split_height_threshold;
 
@@ -107,22 +111,40 @@ 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.  */
+static int scroll_preserve_screen_position;
+
+/* Nonzero means we can split a frame even if it is "unsplittable".  */
+static int inhibit_frame_unsplittable;
+
 #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,
-  "Returns t if OBJ is a window.")
-  (obj)
-     Lisp_Object obj;
+  "Returns t if OBJECT is a window.")
+  (object)
+     Lisp_Object object;
 {
-  return WINDOWP (obj) ? Qt : Qnil;
+  return WINDOWP (object) ? Qt : Qnil;
 }
 
 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
-  "Returns t if OBJ is a window which is currently visible.")
-     (obj)
-     Lisp_Object obj;
+  "Returns t if OBJECT is a window which is currently visible.")
+     (object)
+     Lisp_Object object;
 {
-  return (WINDOWP (obj) && ! NILP (XWINDOW (obj)->buffer) ? Qt : Qnil);
+  return (WINDOWP (object) && ! NILP (XWINDOW (object)->buffer) ? Qt : Qnil);
 }
 
 Lisp_Object
@@ -144,6 +166,7 @@ make_window ()
   XSETFASTINT (p->height, 0);
   XSETFASTINT (p->width, 0);
   XSETFASTINT (p->hscroll, 0);
+  XSETFASTINT (p->last_point, 0);
   XSETFASTINT (p->last_point_x, 0);
   XSETFASTINT (p->last_point_y, 0);
   p->start = Fmake_marker ();
@@ -170,12 +193,10 @@ used by that frame.")
   (frame)
     Lisp_Object frame;
 {
-#ifdef MULTI_FRAME
   if (NILP (frame))
     XSETFRAME (frame, selected_frame);
   else
     CHECK_LIVE_FRAME (frame, 0);
-#endif
 
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
@@ -223,7 +244,8 @@ POS defaults to point; WINDOW, to the selected window.")
   height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
 
   buf = XBUFFER (w->buffer);
-  if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf))
+  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. */
@@ -242,8 +264,17 @@ POS defaults to point; WINDOW, to the selected window.")
        return Qnil;
 
       /* If that info is not correct, calculate afresh */
+      /* BUG FIX for the 7th arg (TOHPOS).
+
+        '0' is harmless, however, ' - (1 << (BITS_PER_SHORT - 1))' is
+        more appropriate here.  In case of HSCROLL > 0, this can avoid
+        needless calculation done until (HPOS == 0).
+
+        We want to determine if the position POSINT is in HEIGHT or
+        not.  We don't have to do calculation until (HPOS == 0).  We
+        can stop it when VPOS goes beyond HEIGHT.  */
       posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0), 0,
-                               posint, height, 0,
+                               posint, height, - (1 << (BITS_PER_SHORT - 1)),
                                window_internal_width (w) - 1,
                                hscroll, 0, w);
 
@@ -307,15 +338,41 @@ NCOL should be zero or positive.")
 
   CHECK_NUMBER (ncol, 1);
   if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
-  if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1)))
-    args_out_of_range (ncol, Qnil);
   w = decode_window (window);
   if (XINT (w->hscroll) != XINT (ncol))
-    clip_changed = 1;          /* Prevent redisplay shortcuts */
+    XBUFFER (w->buffer)->clip_changed = 1; /* Prevent redisplay shortcuts */
   w->hscroll = ncol;
   return ncol;
 }
 
+DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
+       Swindow_redisplay_end_trigger, 0, 1, 0,
+  "Return WINDOW's redisplay end trigger value.\n\
+See `set-window-redisplay-end-trigger' for more information.")
+  (window)
+     Lisp_Object window;
+{
+  return decode_window (window)->redisplay_end_trigger;
+}
+
+DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
+       Sset_window_redisplay_end_trigger, 2, 2, 0,
+  "Set WINDOW's redisplay end trigger value to VALUE.\n\
+VALUE should be a buffer position (typically a marker) or nil.\n\
+If it is a buffer position, then if redisplay in WINDOW reaches a position\n\
+beyond VALUE, the functions in `redisplay-end-trigger-functions' are called\n\
+with two arguments: WINDOW, and the end trigger value.\n\
+Afterwards the end-trigger value is reset to nil.")
+  (window, value)
+     register Lisp_Object window, value;
+{
+  register struct window *w;
+
+  w = decode_window (window);
+  w->redisplay_end_trigger = value;
+  return value;
+}
+
 DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
   "Return a list of the edge coordinates of WINDOW.\n\
 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.\n\
@@ -328,7 +385,7 @@ 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))));
@@ -349,25 +406,28 @@ coordinates_in_window (w, x, y)
      register int *x, *y;
 {
   register int left = XINT (w->left);
-  register int width = XINT (w->width);
+  register int right_edge = WINDOW_RIGHT_EDGE (w);
+  register int left_margin = WINDOW_LEFT_MARGIN (w);
+  register int right_margin = WINDOW_RIGHT_MARGIN (w);
   register int window_height = XINT (w->height);
   register int top = XFASTINT (w->top);
-
-  if (   *x < left || *x >= left + width
+  
+  if (   *x < left || *x >= right_edge
       || *y < top  || *y >= top  + window_height)
     return 0;
 
+  if (left_margin != left && *x < left_margin && *x >= left)
+    return 3;
+  
+  if (right_margin != right_edge && *x >= right_margin && *x < right_edge)
+    return 3;
+  
   /* Is the character is the mode line?  */
   if (*y == top + window_height - 1
       && ! MINI_WINDOW_P (w))
     return 2;
-  
-  /* Is the character in the right border?  */
-  if (*x == left + width - 1
-      && left + width != FRAME_WIDTH (XFRAME (w->frame)))
-    return 3;
 
-  *x -= left;
+  *x -= WINDOW_LEFT_MARGIN (w);
   *y -= top;
   return 1;
 }
@@ -400,11 +460,11 @@ If they are on the border between WINDOW and its right sibling,\n\
       return Qnil;
 
     case 1:                    /* In text part of window. */
-      return Fcons (x, y);
+      return Fcons (make_number (x), make_number (y));
 
     case 2:                    /* In mode line of window. */
       return Qmode_line;
-      
+
     case 3:                    /* On right border of window.  */
       return Qvertical_line;
 
@@ -441,7 +501,7 @@ window_from_coordinates (frame, x, y, part)
       tem = Fnext_window (tem, Qt, Qlambda);
     }
   while (! EQ (tem, first));
-  
+
   return Qnil;
 }
 
@@ -455,12 +515,10 @@ column 0.")
 {
   int part;
 
-#ifdef MULTI_FRAME
   if (NILP (frame))
     XSETFRAME (frame, selected_frame);
   else
     CHECK_LIVE_FRAME (frame, 2);
-#endif
   CHECK_NUMBER (x, 0);
   CHECK_NUMBER (y, 1);
 
@@ -491,7 +549,8 @@ But that is hard to define.")
 }
 
 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
-  "Return position at which display currently starts in WINDOW.")
+  "Return position at which display currently starts in WINDOW.\n\
+This is updated by redisplay or by calling `set-window-start'.")
   (window)
      Lisp_Object window;
 {
@@ -509,13 +568,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);
@@ -533,8 +594,20 @@ 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;
+      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;
 }
@@ -572,6 +645,7 @@ from overriding motion of point in order to display at this exact start.")
     w->force_start = Qt;
   w->update_mode_line = Qt;
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   if (!EQ (window, selected_window))
     windows_or_buffers_changed++;
   return pos;
@@ -621,20 +695,23 @@ DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
    Ignore the specified tables if they are not valid;
    if no valid table is specified, return 0.  */
 
-struct Lisp_Vector *
+struct Lisp_Char_Table *
 window_display_table (w)
      struct window *w;
 {
   Lisp_Object tem;
   tem = w->display_table;
-  if (VECTORP (tem) && XVECTOR (tem)->size == DISP_TABLE_SIZE)
-    return XVECTOR (tem);
+  if (DISP_TABLE_P (tem))
+    return XCHAR_TABLE (tem);
+  if (NILP (w->buffer))
+    return 0;
+
   tem = XBUFFER (w->buffer)->display_table;
-  if (VECTORP (tem) && XVECTOR (tem)->size == DISP_TABLE_SIZE)
-    return XVECTOR (tem);
+  if (DISP_TABLE_P (tem))
+    return XCHAR_TABLE (tem);
   tem = Vstandard_display_table;
-  if (VECTORP (tem) && XVECTOR (tem)->size == DISP_TABLE_SIZE)
-    return XVECTOR (tem);
+  if (DISP_TABLE_P (tem))
+    return XCHAR_TABLE (tem);
   return 0;
 }
 
@@ -653,16 +730,21 @@ 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 (b->last_selected_window))
+    b->last_selected_window = Qnil;
+
 #if 0
   if (w == XWINDOW (selected_window)
       || ! EQ (buf, XWINDOW (selected_window)->buffer))
@@ -676,20 +758,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;
 {
@@ -733,6 +818,19 @@ 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;
@@ -751,7 +849,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))
@@ -858,8 +956,6 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
 
   /* Mark this window as deleted.  */
   p->buffer = p->hchild = p->vchild = Qnil;
-
-  return Qnil;
 }
 \f
 
@@ -915,12 +1011,16 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
   /* minibuf == nil may or may not include minibuffers.
      Decide if it does.  */
   if (NILP (minibuf))
-    minibuf = (minibuf_level ? Qt : Qlambda);
+    minibuf = (minibuf_level ? minibuf_window : Qlambda);
+  else if (! EQ (minibuf, Qt))
+    minibuf = Qlambda;
+  /* Now minibuf can be t => count all minibuffer windows,
+     lambda => count none of them,
+     or a specific minibuffer window (the active one) to count.  */
 
-#ifdef MULTI_FRAME
   /* all_frames == nil doesn't specify which frames to include.  */
   if (NILP (all_frames))
-    all_frames = (EQ (minibuf, Qt)
+    all_frames = (! EQ (minibuf, Qlambda)
                  ? (FRAME_MINIBUF_WINDOW
                     (XFRAME
                      (WINDOW_FRAME
@@ -941,7 +1041,6 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
      visible meaning search just visible frames,
      0 meaning search visible and iconified frames,
      or a window, meaning search the frame that window belongs to.  */
-#endif
 
   /* Do this loop at least once, to get the next window, and perhaps
      again, if we hit the minibuffer and that is not acceptable.  */
@@ -957,7 +1056,6 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
            /* We've reached the end of this frame.
               Which other frames are acceptable?  */
            tem = WINDOW_FRAME (XWINDOW (window));
-#ifdef MULTI_FRAME
            if (! NILP (all_frames))
              {
                Lisp_Object tem1;
@@ -972,7 +1070,6 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
                if (EQ (tem, tem1))
                  XSETFRAME (tem, selected_frame);
              }
-#endif
            tem = FRAME_ROOT_WINDOW (XFRAME (tem));
 
            break;
@@ -991,13 +1088,15 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
          else break;
        }
     }
-  /* Which windows are acceptible?
+  /* Which windows are acceptable?
      Exit the loop and accept this window if
-     this isn't a minibuffer window, or
-     we're accepting minibuffer windows, or
+     this isn't a minibuffer window,
+     or we're accepting all minibuffer windows,
+     or this is the active minibuffer and we are accepting that one, or
      we've come all the way around and we're back at the original window.  */
   while (MINI_WINDOW_P (XWINDOW (window))
         && ! EQ (minibuf, Qt)
+        && ! EQ (minibuf, window)
         && ! EQ (window, start_window));
 
   return window;
@@ -1008,7 +1107,7 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
    due to limits in the Unix cpp.
 
 DEFUN ("previous-window", Ffoo, Sfoo, 0, 3, 0,
-  "Return the window preceeding WINDOW in canonical ordering of windows.\n\
+  "Return the window preceding WINDOW in canonical ordering of windows.\n\
 If omitted, WINDOW defaults to the selected window.\n\
 \n\
 Optional second arg MINIBUF t means count the minibuffer window even\n\
@@ -1054,13 +1153,17 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
   /* minibuf == nil may or may not include minibuffers.
      Decide if it does.  */
   if (NILP (minibuf))
-    minibuf = (minibuf_level ? Qt : Qlambda);
+    minibuf = (minibuf_level ? minibuf_window : Qlambda);
+  else if (! EQ (minibuf, Qt))
+    minibuf = Qlambda;
+  /* Now minibuf can be t => count all minibuffer windows,
+     lambda => count none of them,
+     or a specific minibuffer window (the active one) to count.  */
 
-#ifdef MULTI_FRAME
   /* all_frames == nil doesn't specify which frames to include.
      Decide which frames it includes.  */
   if (NILP (all_frames))
-    all_frames = (EQ (minibuf, Qt)
+    all_frames = (! EQ (minibuf, Qlambda)
                   ? (FRAME_MINIBUF_WINDOW
                      (XFRAME
                       (WINDOW_FRAME
@@ -1081,7 +1184,6 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
      visible meaning search just visible frames,
      0 meaning search visible and iconified frames,
      or a window, meaning search the frame that window belongs to.  */
-#endif
 
   /* Do this loop at least once, to get the previous window, and perhaps
      again, if we hit the minibuffer and that is not acceptable.  */
@@ -1097,7 +1199,6 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
            /* We have found the top window on the frame.
               Which frames are acceptable?  */
            tem = WINDOW_FRAME (XWINDOW (window));
-#ifdef MULTI_FRAME
            if (! NILP (all_frames))
              /* It's actually important that we use prev_frame here,
                 rather than next_frame.  All the windows acceptable
@@ -1121,7 +1222,6 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
                if (EQ (tem, tem1))
                  XSETFRAME (tem, selected_frame);
              }
-#endif
            /* If this frame has a minibuffer, find that window first,
               because it is conceptually the last window in that frame.  */
            if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
@@ -1148,12 +1248,14 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
     }
   /* Which windows are acceptable?
      Exit the loop and accept this window if
-     this isn't a minibuffer window, or
-     we're accepting minibuffer windows, or
+     this isn't a minibuffer window,
+     or we're accepting all minibuffer windows,
+     or this is the active minibuffer and we are accepting that one, or
      we've come all the way around and we're back at the original window.  */
   while (MINI_WINDOW_P (XWINDOW (window))
-        && !EQ (minibuf, Qt)
-        && !EQ (window, start_window));
+        && ! EQ (minibuf, Qt)
+        && ! EQ (minibuf, window)
+        && ! EQ (window, start_window));
 
   return window;
 }
@@ -1164,15 +1266,15 @@ All windows on current frame are arranged in a cyclic order.\n\
 This command selects the window ARG steps away in that order.\n\
 A negative ARG moves in the opposite order.  If the optional second\n\
 argument ALL_FRAMES is non-nil, cycle through all frames.")
-  (n, all_frames)
-     register Lisp_Object n, all_frames;
+  (arg, all_frames)
+     register Lisp_Object arg, all_frames;
 {
   register int i;
   register Lisp_Object w;
 
-  CHECK_NUMBER (n, 0);
+  CHECK_NUMBER (arg, 0);
   w = selected_window;
-  i = XINT (n);
+  i = XINT (arg);
 
   while (i > 0)
     {
@@ -1205,7 +1307,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
@@ -1222,7 +1325,6 @@ window_loop (type, obj, mini, frames)
   Lisp_Object frame_arg;
   frame_arg = Qt;
 
-#ifdef MULTI_FRAME
   /* If we're only looping through windows on a particular frame,
      frame points to that frame.  If we're looping through windows
      on all frames, frame is 0.  */
@@ -1238,9 +1340,6 @@ window_loop (type, obj, mini, frames)
     frame_arg = frames;
   else if (EQ (frames, Qvisible))
     frame_arg = frames;
-#else
-  frame = 0;
-#endif
 
   /* frame_arg is Qlambda to stick to one frame,
      Qvisible to consider all visible frames,
@@ -1276,18 +1375,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))
@@ -1307,7 +1411,6 @@ window_loop (type, obj, mini, frames)
          case DELETE_BUFFER_WINDOWS:
            if (EQ (XWINDOW (w)->buffer, obj))
              {
-#ifdef MULTI_FRAME
                FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
 
                /* If this window is dedicated, and in a frame of its own,
@@ -1336,13 +1439,13 @@ window_loop (type, obj, mini, frames)
                    Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
                  }
                else
-#endif
                  /* If we're deleting the buffer displayed in the only window
                     on the frame, find a new buffer to display there.  */
                  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*"));
@@ -1377,11 +1480,10 @@ 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*"));
-#ifdef MULTI_FRAME
                /* If this window is dedicated, and in a frame of its own,
                   kill the frame.  */
                if (EQ (w, FRAME_ROOT_WINDOW (f))
@@ -1408,7 +1510,6 @@ window_loop (type, obj, mini, frames)
                    Fdelete_frame (WINDOW_FRAME (XWINDOW (w)), Qnil);
                  }
                else
-#endif
                  {
                    /* Otherwise show a different buffer in the window.  */
                    XWINDOW (w)->dedicated = Qnil;
@@ -1418,6 +1519,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))
@@ -1427,7 +1534,14 @@ window_loop (type, obj, mini, frames)
     }
 
   return best_window;
-}     
+}
+
+/* Used for debugging.  Abort if any window has a dead buffer.  */
+
+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\
@@ -1526,10 +1640,14 @@ 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->optional_new_start = Qt;
 
       set_buffer_internal (obuf);
     }
@@ -1540,21 +1658,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;
 {
-#ifdef MULTI_FRAME
   /* FRAME uses t and nil to mean the opposite of what window_loop
      expects.  */
-  if (! FRAMEP (frame))
-    frame = NILP (frame) ? Qt : Qnil;
-#else
-  frame = Qt;
-#endif
+  if (NILP (frame))
+    frame = Qt;
+  else if (EQ (frame, Qt))
+    frame = Qnil;
 
   if (!NILP (buffer))
     {
@@ -1580,6 +1697,26 @@ DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
     }
   return Qnil;
 }
+
+/* Replace BUFFER with some other buffer in all windows
+   of all frames, even those on other keyboards.  */
+
+void
+replace_buffer_in_all_windows (buffer)
+     Lisp_Object buffer;
+{
+#ifdef MULTI_KBOARD
+  Lisp_Object tail, frame;
+
+  /* A single call to window_loop won't do the job
+     because it only considers frames on the current keyboard.
+     So loop manually over frames, and handle each one.  */
+  FOR_EACH_FRAME (tail, frame)
+    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
+#else
+  window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
+#endif
+}
 \f
 /* Set the height of WINDOW and all its inferiors.  */
 
@@ -1609,7 +1746,7 @@ check_frame_size (frame, rows, cols)
      int *rows, *cols;
 {
   /* For height, we have to see:
-     whether the frame has a minibuffer, 
+     whether the frame has a minibuffer,
      whether it wants a mode line, and
      whether it has a menu bar.  */
   int min_height =
@@ -1629,6 +1766,7 @@ check_frame_size (frame, rows, cols)
    nodelete nonzero means do not do this.
    (The caller should check later and do so if appropriate)  */
 
+void
 set_window_height (window, height, nodelete)
      Lisp_Object window;
      int height;
@@ -1644,13 +1782,16 @@ set_window_height (window, height, nodelete)
 
   if (!nodelete
       && ! NILP (w->parent)
-      && height < window_min_height)
+      && (MINI_WINDOW_P (w)
+         ? height < 1
+         : height < window_min_height))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   windows_or_buffers_changed++;
   FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
 
@@ -1696,6 +1837,7 @@ set_window_height (window, height, nodelete)
 
 /* Recursively set width of WINDOW and its inferiors. */
 
+void
 set_window_width (window, width, nodelete)
      Lisp_Object window;
      int width;
@@ -1709,11 +1851,12 @@ set_window_width (window, width, nodelete)
 
   if (!nodelete && width < window_min_width && !NILP (w->parent))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   windows_or_buffers_changed++;
   FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
 
@@ -1758,6 +1901,14 @@ set_window_width (window, width, nodelete)
 \f
 int window_select_count;
 
+Lisp_Object
+Fset_window_buffer_unwind (obuf)
+     Lisp_Object obuf;
+{
+  Fset_buffer (obuf);
+  return 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.")
@@ -1766,6 +1917,7 @@ BUFFER can be a buffer or buffer name.")
 {
   register Lisp_Object tem;
   register struct window *w = decode_window (window);
+  int count = specpdl_ptr - specpdl;
 
   buffer = Fget_buffer (buffer);
   CHECK_BUFFER (buffer, 1);
@@ -1787,31 +1939,71 @@ BUFFER can be a buffer or buffer name.")
     }
 
   w->buffer = buffer;
+
+  if (EQ (window, selected_window))
+    XBUFFER (w->buffer)->last_selected_window = window;
+
+  /* Update time stamps of buffer display.  */
+  if (INTEGERP (XBUFFER (buffer)->display_count))
+    XSETINT (XBUFFER (buffer)->display_count,
+            XINT (XBUFFER (buffer)->display_count) + 1);
+  XBUFFER (buffer)->display_time = Fcurrent_time ();
+
   XSETFASTINT (w->window_end_pos, 0);
   w->window_end_valid = Qnil;
-  XSETFASTINT(w->hscroll, 0);
-  Fset_marker (w->pointm,
-              make_number (BUF_PT (XBUFFER (buffer))),
-              buffer);
+  XSETFASTINT (w->hscroll, 0);
+  set_marker_both (w->pointm, buffer,
+                  BUF_PT (XBUFFER (buffer)), BUF_PT_BYTE (XBUFFER (buffer)));
   set_marker_restricted (w->start,
                         make_number (XBUFFER (buffer)->last_window_start),
                         buffer);
   w->start_at_line_beg = Qnil;
   w->force_start = Qnil;
   XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
   windows_or_buffers_changed++;
+
+  /* We must select BUFFER for running the window-scroll-functions.
+     If WINDOW is selected, switch permanently.
+     Otherwise, switch but go back to the ambient buffer afterward.  */
   if (EQ (window, selected_window))
     Fset_buffer (buffer);
+  /* We can't check ! NILP (Vwindow_scroll_functions) here
+     because that might itself be a local variable.  */
+  else if (window_initialized)
+    {
+      record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
+      Fset_buffer (buffer);
+    }
+
+  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);
 
   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);
@@ -1827,11 +2019,12 @@ 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;
-#ifdef MULTI_FRAME
   if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
     {
       XFRAME (WINDOW_FRAME (w))->selected_window = window;
@@ -1843,11 +2036,13 @@ before each command.")
     }
   else
     selected_frame->selected_window = window;
-#endif
 
-  record_buffer (w->buffer);
+  if (recordflag)
+    record_buffer (w->buffer);
   Fset_buffer (w->buffer);
 
+  XBUFFER (w->buffer)->last_selected_window = window;
+
   /* Go to the point recorded in the window.
      This is important when the buffer is in more
      than one window.  It also matters when
@@ -1866,18 +2061,124 @@ 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.
+
+   The reason for the exception for the selected frame
+   is that it seems better not to change the selected frames visibility
+   merely because of displaying a different buffer in it.
+   The deiconification is useful when a buffer gets shown in
+   another frame that you were not using lately.  */
+
+static Lisp_Object
+display_buffer_1 (window)
+     Lisp_Object window;
+{
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+  FRAME_SAMPLE_VISIBILITY (f);
+  if (f != selected_frame)
+    {
+      if (FRAME_ICONIFIED_P (f))
+       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
+      else if (FRAME_VISIBLE_P (f))
+       Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
+    }
+  return window;
+}
+
+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;
+}
 
-DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
-       "bDisplay buffer: \nP",
+   /* 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\
 unless the window is the selected window and the optional second\n\
 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.\n\
-Returns the window displaying BUFFER.")
-  (buffer, not_this_window)
-     register Lisp_Object buffer, not_this_window;
+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.\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;
 
@@ -1889,120 +2190,67 @@ Returns the window displaying BUFFER.")
 
   if (NILP (not_this_window)
       && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
-    return selected_window;
+    return display_buffer_1 (selected_window);
 
   /* See if the user has specified this buffer should appear
      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 selected_window;
-       }
-
-      tem = Fassoc (XBUFFER (buffer)->name, Vsame_window_buffer_names);
+      tem = Fsame_window_p (XBUFFER (buffer)->name);
       if (!NILP (tem))
        {
          Fswitch_to_buffer (buffer, Qnil);
-         return 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 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 selected_window;
-           }
+         return display_buffer_1 (selected_window);
        }
     }
 
-#ifdef MULTI_FRAME
   /* 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
-#endif
     XSETFRAME (tem, last_nonminibuf_frame);
   window = Fget_buffer_window (buffer, tem);
   if (!NILP (window)
       && (NILP (not_this_window) || !EQ (window, selected_window)))
     {
-#ifdef MULTI_FRAME
-      if (FRAME_ICONIFIED_P (XFRAME (WINDOW_FRAME (XWINDOW (window)))))
-       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
-#endif
-      return window;
+      return display_buffer_1 (window);
     }
 
   /* Certain buffer names get special handling.  */
-  if (! NILP (Vspecial_display_function))
+  if (!NILP (Vspecial_display_function))
     {
-      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);
     }
 
-#ifdef MULTI_FRAME
   /* If there are no frames open that have more than a minibuffer,
      we need to create a new frame.  */
   if (pop_up_frames || last_nonminibuf_frame == 0)
     {
       window = Fframe_selected_window (call0 (Vpop_up_frame_function));
       Fset_window_buffer (window, buffer);
-      return window;
+      return display_buffer_1 (window);
     }
-#endif /* MULTI_FRAME */
 
   if (pop_up_windows
-#ifdef MULTI_FRAME
       || FRAME_MINIBUF_ONLY_P (selected_frame)
       /* If the current frame is a special display frame,
         don't try to reuse its windows.  */
       || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
-#endif
       )
     {
       Lisp_Object frames;
 
-      frames = Qnil;      
-#ifdef MULTI_FRAME
+      frames = Qnil;
       if (FRAME_MINIBUF_ONLY_P (selected_frame))
        XSETFRAME (frames, last_nonminibuf_frame);
-#endif
       /* Don't try to create a window if would get an error */
       if (split_height_threshold < window_min_height << 1)
        split_height_threshold = window_min_height << 1;
@@ -2011,7 +2259,6 @@ Returns the window displaying BUFFER.")
         ignore minibuffers and dedicated windows.
         This means they can return nil.  */
 
-#ifdef MULTI_FRAME
       /* If the frame we would try to split cannot be split,
         try other frames.  */
       if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
@@ -2026,7 +2273,6 @@ Returns the window displaying BUFFER.")
            window = Fget_largest_window (Qt);
        }
       else
-#endif
        window = Fget_largest_window (frames);
 
       /* If we got a tall enough full-width window that can be split,
@@ -2034,8 +2280,7 @@ Returns the window displaying BUFFER.")
       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
        {
@@ -2050,25 +2295,26 @@ Returns the window displaying BUFFER.")
                  || EQ (XWINDOW (window)->parent, Qnil))
              && window_height (window) >= window_min_height << 1)
            window = Fsplit_window (window, Qnil, Qnil);
-#ifdef MULTI_FRAME
          /* 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.  */
          if (NILP (window))
            window = Fframe_selected_window (call0 (Vpop_up_frame_function));
-#else
-         /* As a last resort, use a non minibuffer window.  */
-         if (NILP (window))
-           window = Fframe_first_window (Fselected_frame ());
-#endif
          /* If window appears above or below another,
             even out their heights.  */
          other = upper = lower = Qnil;
@@ -2078,15 +2324,19 @@ Returns the window displaying BUFFER.")
            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;
+             int total = (XFASTINT (XWINDOW (other)->height)
+                          + XFASTINT (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);
+             change_window_height ((total / 2
+                                    - XFASTINT (XWINDOW (upper)->height)),
+                                   0);
              selected_window = old_selected_window;
            }
        }
@@ -2095,7 +2345,7 @@ Returns the window displaying BUFFER.")
     window = Fget_lru_window (Qnil);
 
   Fset_window_buffer (window, buffer);
-  return window;
+  return display_buffer_1 (window);
 }
 
 void
@@ -2106,31 +2356,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);
-  clip_changed = 1;
+  XBUFFER (buf)->clip_changed = 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);
 
-#ifdef MULTI_FRAME
       if (XFRAME (XWINDOW (window)->frame) != selected_frame)
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
-#endif /* MULTI_FRAME */
       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;
@@ -2141,13 +2392,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);
                }
            }
@@ -2155,7 +2408,7 @@ temp_output_buffer_show (buf)
     }
 }
 \f
-static
+static void
 make_dummy_parent (window)
      Lisp_Object window;
 {
@@ -2191,14 +2444,16 @@ make_dummy_parent (window)
 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 HOR-FLAG is non-nil, split side by side\n\
-and put SIZE columns in the first of the pair.")
-  (window, chsize, horflag)
-     Lisp_Object window, chsize, horflag;
+If optional third arg HORFLAG is non-nil, split side by side\n\
+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;
 {
   register Lisp_Object new;
   register struct window *o, *p;
-  register int size;
+  FRAME_PTR fo;
+  register int size_int;
 
   if (NILP (window))
     window = selected_window;
@@ -2206,36 +2461,35 @@ and put SIZE columns in the first of the pair.")
     CHECK_LIVE_WINDOW (window, 0);
 
   o = XWINDOW (window);
+  fo = XFRAME (WINDOW_FRAME (o));
 
-  if (NILP (chsize))
+  if (NILP (size))
     {
       if (!NILP (horflag))
-       /* Round odd size up, since this is for the left-hand window,
-          and it will lose a column for the separators.  */
-       size = ((XFASTINT (o->width) + 1) & -2) >> 1;
+       /* Calculate the size of the left-hand window, by dividing
+          the usable space in columns by two. */
+       size_int = XFASTINT (o->width) >> 1;
       else
-       size = XFASTINT (o->height) >> 1;
+       size_int = XFASTINT (o->height) >> 1;
     }
   else
     {
-      CHECK_NUMBER (chsize, 1);
-      size = XINT (chsize);
+      CHECK_NUMBER (size, 1);
+      size_int = XINT (size);
     }
 
   if (MINI_WINDOW_P (o))
     error ("Attempt to split minibuffer window");
-  else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
-    error ("Attempt to split unsplittable frame");
 
   check_min_window_sizes ();
 
   if (NILP (horflag))
     {
-      if (size < window_min_height)
-       error ("Window height %d too small (after splitting)", size);
-      if (size + window_min_height > XFASTINT (o->height))
-       error ("Window height %d too small (after splitting)", 
-              XFASTINT (o->height) - size);
+      if (size_int < window_min_height)
+       error ("Window height %d too small (after splitting)", size_int);
+      if (size_int + window_min_height > XFASTINT (o->height))
+       error ("Window height %d too small (after splitting)",
+              XFASTINT (o->height) - size_int);
       if (NILP (o->parent)
          || NILP (XWINDOW (o->parent)->vchild))
        {
@@ -2246,11 +2500,12 @@ and put SIZE columns in the first of the pair.")
     }
   else
     {
-      if (size < window_min_width)
-       error ("Window width %d too small (after splitting)", size);
-      if (size + window_min_width > XFASTINT (o->width))
-       error ("Window width %d too small (after splitting)", 
-              XFASTINT (o->width) - size);
+      if (size_int < window_min_width)
+       error ("Window width %d too small (after splitting)", size_int);
+
+      if (size_int + window_min_width > XFASTINT (o->width))
+       error ("Window width %d too small (after splitting)",
+              XFASTINT (o->width) - size_int);
       if (NILP (o->parent)
          || NILP (XWINDOW (o->parent)->hchild))
        {
@@ -2265,7 +2520,7 @@ and put SIZE columns in the first of the pair.")
      if we are making side-by-side windows */
 
   windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (o))) = 1;
+  FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
   new = make_window ();
   p = XWINDOW (new);
 
@@ -2278,49 +2533,57 @@ and put SIZE columns in the first of the pair.")
   p->parent = o->parent;
   p->buffer = Qt;
 
-  Fset_window_buffer (new, o->buffer);
-
   /* Apportion the available frame space among the two new windows */
 
   if (!NILP (horflag))
     {
       p->height = o->height;
       p->top = o->top;
-      XSETFASTINT (p->width, XFASTINT (o->width) - size);
-      XSETFASTINT (o->width, size);
-      XSETFASTINT (p->left, XFASTINT (o->left) + size);
+      XSETFASTINT (p->width, XFASTINT (o->width) - size_int);
+      XSETFASTINT (o->width, size_int);
+      XSETFASTINT (p->left, XFASTINT (o->left) + size_int);
     }
   else
     {
       p->left = o->left;
       p->width = o->width;
-      XSETFASTINT (p->height, XFASTINT (o->height) - size);
-      XSETFASTINT (o->height, size);
-      XSETFASTINT (p->top, XFASTINT (o->top) + size);
+      XSETFASTINT (p->height, XFASTINT (o->height) - size_int);
+      XSETFASTINT (o->height, size_int);
+      XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
     }
 
+  Fset_window_buffer (new, o->buffer);
+
   return new;
 }
 \f
 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
   "Make current window ARG lines bigger.\n\
 From program, optional second arg non-nil means grow sideways ARG columns.")
-  (n, side)
-     register Lisp_Object n, side;
+  (arg, side)
+     register Lisp_Object arg, side;
 {
-  CHECK_NUMBER (n, 0);
-  change_window_height (XINT (n), !NILP (side));
+  CHECK_NUMBER (arg, 0);
+  change_window_height (XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p",
   "Make current window ARG lines smaller.\n\
-From program, optional second arg non-nil means shrink sideways ARG columns.")
-  (n, side)
-     register Lisp_Object n, side;
+From program, optional second arg non-nil means shrink sideways arg columns.")
+  (arg, side)
+     register Lisp_Object arg, side;
 {
-  CHECK_NUMBER (n, 0);
-  change_window_height (-XINT (n), !NILP (side));
+  CHECK_NUMBER (arg, 0);
+  change_window_height (-XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
@@ -2355,6 +2618,7 @@ window_width (window)
    also changes the heights of the siblings so as to
    keep everything consistent. */
 
+void
 change_window_height (delta, widthflag)
      register int delta;
      int widthflag;
@@ -2363,10 +2627,12 @@ change_window_height (delta, widthflag)
   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);
+  int (*sizefun) P_ ((Lisp_Object))
+    = widthflag ? window_width : window_height;
+  register void (*setsizefun) P_ ((Lisp_Object, int, int))
+    = (widthflag ? set_window_width : set_window_height);
+  int maximum;
+  Lisp_Object next, prev;
 
   check_min_window_sizes ();
 
@@ -2408,29 +2674,78 @@ change_window_height (delta, widthflag)
 
   if (*sizep + delta < MINSIZE (window))
     {
-      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) - MINSIZE (next);
+  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+    maximum += (*sizefun) (prev) - MINSIZE (prev);
+
+  /* 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;
+
+      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)
+       {
+         if (delta == 0)
+           break;
+         if (! NILP (next))
+           {
+             int this_one = (*sizefun) (next) - MINSIZE (next);
+             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) - MINSIZE (prev);
+             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;
+           }
+       }
+
+      /* 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
     {
@@ -2463,6 +2778,7 @@ change_window_height (delta, widthflag)
     }
 
   XSETFASTINT (p->last_modified, 0);
+  XSETFASTINT (p->last_overlay_modified, 0);
 }
 #undef MINSIZE
 #undef CURBEG
@@ -2497,42 +2813,50 @@ window_internal_width (w)
      struct window *w;
 {
   FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
-  int left = XINT (w->left);
   int width = XINT (w->width);
 
-  /* 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;
-
-  /* If we are not flush right, then our rightmost columns are
-     occupied by some sort of separator.  */
-
   /* Scroll bars occupy a few columns.  */
   if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
     return width - FRAME_SCROLL_BAR_COLS (f);
 
   /* The column of `|' characters separating side-by-side windows
      occupies one column only.  */
-  return width - 1;
+  if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+    return width - 1;
+
+  return width;
 }
 
 
-/* Scroll contents of window WINDOW up N lines.  */
+/* Scroll contents of window WINDOW up N lines.
+   If WHOLE is nonzero, it means scroll N screenfuls instead.  */
 
-void
-window_scroll (window, n, noerror)
+static void
+window_scroll (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_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;
+  int startpos;
+  struct position posit;
+  int original_vpos;
+
+  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);
@@ -2540,17 +2864,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);
-      w->force_start = Qt;
+      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)
     {
@@ -2562,20 +2885,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);
-      if (pos > opoint)
-       SET_PT (pos);
-      if (n < 0)
+      XSETFASTINT (w->last_overlay_modified, 0);
+      /* Set force_start so that redisplay_window will run
+        the window-scroll-functions.  */
+      w->force_start = Qt;
+
+      if (whole && scroll_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 (scroll_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 (scroll_preserve_screen_position)
+               {
+                 SET_PT_BOTH (pos, pos_byte);
+                 Fvertical_motion (make_number (original_vpos), window);
+               }
+             else
+               Fvertical_motion (make_number (-1), window);
+           }
        }
     }
   else
@@ -2610,13 +2992,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);
@@ -2626,23 +3008,25 @@ 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.")
-  (n)
-     Lisp_Object 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 `-'.")
+  (arg)
+     Lisp_Object arg;
 {
-  scroll_command (n, 1);
+  scroll_command (arg, 1);
   return Qnil;
 }
 
 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.")
-  (n)
-     Lisp_Object n;
+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;
 {
-  scroll_command (n, -1);
+  scroll_command (arg, -1);
   return Qnil;
 }
 \f
@@ -2664,7 +3048,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
     {
@@ -2691,16 +3075,18 @@ 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\
 If `other-window-scroll-buffer' is non-nil, scroll the window\n\
 showing that buffer, popping the buffer up if necessary.")
-  (n)
-     register Lisp_Object n;
+  (arg)
+     register Lisp_Object arg;
 {
   register Lisp_Object window;
   register int defalt;
@@ -2719,19 +3105,19 @@ showing that buffer, popping the buffer up if necessary.")
   Fset_buffer (w->buffer);
   SET_PT (marker_position (w->pointm));
 
-  if (NILP (n))
-    window_scroll (window, defalt, 1);
-  else if (EQ (n, Qminus))
-    window_scroll (window, -defalt, 1);
+  if (NILP (arg))
+    window_scroll (window, defalt, 1, 1);
+  else if (EQ (arg, Qminus))
+    window_scroll (window, -defalt, 1, 1);
   else
     {
-      if (CONSP (n))
-       n = Fcar (n);
-      CHECK_NUMBER (n, 0);
-      window_scroll (window, XINT (n), 1);
+      if (CONSP (arg))
+       arg = Fcar (arg);
+      CHECK_NUMBER (arg, 0);
+      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;
@@ -2776,42 +3162,46 @@ DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
   "Center point in window and redisplay frame.  With ARG, put point on line ARG.\n\
 The desired position of point is always relative to the current window.\n\
 Just C-u as prefix means put point in the center of the window.\n\
-No arg (i.e., it is nil) erases the entire frame and then\n\
+If ARG is omitted or nil, erases the entire frame and then\n\
 redraws with point in the center of the current window.")
-  (n)
-     register Lisp_Object n;
+  (arg)
+     register Lisp_Object arg;
 {
   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 (n))
+  if (NILP (arg))
     {
       extern int frame_garbaged;
 
       SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
-      XSETFASTINT (n, ht / 2);
+      XSETFASTINT (arg, ht / 2);
     }
-  else if (CONSP (n)) /* Just C-u. */
+  else if (CONSP (arg)) /* Just C-u. */
     {
-      XSETFASTINT (n, ht / 2);
+      XSETFASTINT (arg, ht / 2);
     }
   else
     {
-      n = Fprefix_numeric_value (n);
-      CHECK_NUMBER (n, 0);
+      arg = Fprefix_numeric_value (arg);
+      CHECK_NUMBER (arg, 0);
     }
 
-  if (XINT (n) < 0)
-    XSETINT (n, XINT (n) + ht);
+  if (XINT (arg) < 0)
+    XSETINT (arg, XINT (arg) + ht);
 
-  pos = *vmotion (point, - XINT (n), w);
+  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;
 }
@@ -2820,8 +3210,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;
 {
@@ -2844,19 +3234,19 @@ 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
 struct save_window_data
   {
-    int size_from_Lisp_Vector_struct;
+    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 selected_frame;
@@ -2868,15 +3258,16 @@ 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 */
-    int size_from_Lisp_Vector_struct;
+    EMACS_INT size_from_Lisp_Vector_struct;
     struct Lisp_Vector *next_from_Lisp_Vector_struct;
 
     Lisp_Object window;
@@ -2892,22 +3283,40 @@ 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-configration object.")
-  (obj)
-     Lisp_Object obj;
+  "Return t if OBJECT is a window-configuration object.")
+  (object)
+     Lisp_Object object;
 {
-  if (WINDOW_CONFIGURATIONP (obj))
+  if (WINDOW_CONFIGURATIONP (object))
     return Qt;
   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;
@@ -2915,12 +3324,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);
@@ -2928,6 +3335,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);
@@ -2948,15 +3361,29 @@ by `current-window-configuration' (which see).")
       int previous_frame_width =  FRAME_WIDTH  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_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);
-#ifdef HAVE_X_WINDOWS
+       change_frame_size (f, XFASTINT (data->frame_height),
+                          XFASTINT (data->frame_width), 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));
 #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;
 
@@ -2968,7 +3395,7 @@ by `current-window-configuration' (which see).")
       /* Kludge Alert!
         Mark all windows now on frame as "deleted".
         Restoring the new configuration "undeletes" any that are in it.
-        
+
         Save their current buffers in their height fields, since we may
         need it later, if a buffer saved in the configuration is now
         dead.  */
@@ -3021,6 +3448,7 @@ by `current-window-configuration' (which see).")
          w->hscroll = p->hscroll;
          w->display_table = p->display_table;
          XSETFASTINT (w->last_modified, 0);
+         XSETFASTINT (w->last_overlay_modified, 0);
 
          /* Reinstall the saved buffer and pointers into it.  */
          if (NILP (p->buffer))
@@ -3032,14 +3460,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
@@ -3067,10 +3491,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;
                }
            }
@@ -3078,21 +3501,19 @@ 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;
 
-#ifdef MULTI_FRAME
       if (NILP (data->focus_frame)
          || (FRAMEP (data->focus_frame)
              && FRAME_LIVE_P (XFRAME (data->focus_frame))))
        Fredirect_frame_focus (frame, data->focus_frame);
-#endif
 
 #if 0 /* I don't understand why this is needed, and it causes problems
          when the frame's old selected window has been deleted.  */
-#ifdef MULTI_FRAME
-      if (f != selected_frame && ! FRAME_TERMCAP_P (f))
+      if (f != selected_frame && FRAME_WINDOW_P (f))
        do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
                         Qnil, 0);
-#endif
 #endif
 
       /* Set the screen height to the value it had before this function.  */
@@ -3100,31 +3521,45 @@ by `current-window-configuration' (which see).")
          || previous_frame_width != FRAME_WIDTH (f))
        change_frame_size (f, previous_frame_height, previous_frame_width,
                           0, 0);
-#ifdef HAVE_X_WINDOWS
+#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));
 #endif
+
+      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);
 
-#ifdef MULTI_FRAME
-  /* 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);
-#endif
-
-  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
@@ -3143,6 +3578,9 @@ delete_all_subwindows (w)
 
   w->height = w->buffer;       /* See Fset_window_configuration for excuse.  */
 
+  if (!NILP (w->buffer))
+    unshow_buffer (w);
+
   /* We set all three of these fields to nil, to make sure that we can
      distinguish this dead window from any live window.  Live leaf
      windows will have buffer set, and combination windows will have
@@ -3198,17 +3636,18 @@ 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);
+           p->pointm = Fcopy_marker (w->pointm, Qnil);
 
-         p->start = Fcopy_marker (w->start);
+         p->start = Fcopy_marker (w->start, Qnil);
          p->start_at_line_beg = w->start_at_line_beg;
 
          tem = XBUFFER (w->buffer)->mark;
-         p->mark = Fcopy_marker (tem);
+         p->mark = Fcopy_marker (tem, Qnil);
        }
       else
        {
@@ -3237,8 +3676,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\
@@ -3275,9 +3714,7 @@ 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));
-#ifdef MULTI_FRAME
   XSETFRAME (data->selected_frame, selected_frame);
-#endif
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
   data->minibuf_scroll_window = Vminibuf_scroll_window;
@@ -3316,71 +3753,149 @@ Does not restore the value of point in current buffer.")
   return unbind_to (count, val);
 }
 \f
-init_window_once ()
-{
-#ifdef MULTI_FRAME
-  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;
-#else /* not MULTI_FRAME */
-  extern Lisp_Object get_minibuffer ();
+/* Return 1 if window configurations C1 and C2
+   describe the same state of affairs.  This is used by Fequal.   */
 
-  selected_frame = last_nonminibuf_frame = &the_only_frame;
-
-  minibuf_window = make_window ();
-  FRAME_ROOT_WINDOW (selected_frame) = make_window ();
+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;
 
-  XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->next = minibuf_window;
-  XWINDOW (minibuf_window)->prev = FRAME_ROOT_WINDOW (selected_frame);
-  XWINDOW (minibuf_window)->mini_p = Qt;
+  d1 = (struct save_window_data *) XVECTOR (c1);
+  d2 = (struct save_window_data *) XVECTOR (c2);
+  sw1 = XVECTOR (d1->saved_windows);
+  sw2 = XVECTOR (d2->saved_windows);
 
-  /* These values 9 and 10 are arbitrary,
-     just so that there is "something there."
-     Correct values are put in in init_xdisp */
+  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;
 
-  XSETFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->width, 10);
-  XSETFASTINT (XWINDOW (minibuf_window)->width, 10);
+  /* Verify that the two confis have the same number of windows.  */
+  if (sw1->size != sw2->size)
+    return 0;
 
-  XSETFASTINT (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->height, 9);
-  XSETFASTINT (XWINDOW (minibuf_window)->top, 9);
-  XSETFASTINT (XWINDOW (minibuf_window)->height, 1);
+  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;
+       }
+    }
 
-  /* Prevent error in Fset_window_buffer.  */
-  XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->buffer = Qt;
-  XWINDOW (minibuf_window)->buffer = Qt;
+  return 1;
+}
 
-  /* Now set them up for real.  */
-  Fset_window_buffer (FRAME_ROOT_WINDOW (selected_frame),
-                     Fcurrent_buffer ());
-  Fset_window_buffer (minibuf_window, get_minibuffer (0));
+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;
 
-  selected_window = FRAME_ROOT_WINDOW (selected_frame);
-  /* Make sure this window seems more recently used than
-     a newly-created, never-selected window.  Increment
-     window_select_count so the first selection ever will get
-     something newer than this.  */
-  XSETFASTINT (XWINDOW (selected_window)->use_time, ++window_select_count);
-#endif /* not MULTI_FRAME */
+  window_initialized = 1;
 }
 
+void
 syms_of_window ()
 {
+  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);
 
   Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
   staticpro (&Qtemp_buffer_show_hook);
 
-#ifndef MULTI_FRAME
-  /* Make sure all windows get marked */
-  staticpro (&minibuf_window);
-#endif
-
   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
     "Non-nil means call as function to display a help buffer.\n\
 The function is called with one argument, the buffer to be displayed.\n\
@@ -3420,14 +3935,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,
@@ -3436,12 +3957,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,
@@ -3504,6 +4031,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_BOOL ("scroll-preserve-screen-position",
+              &scroll_preserve_screen_position,
+    "*Nonzero means scroll commands move point to keep its screen line unchanged.");
+  scroll_preserve_screen_position = 0;
+
+  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);
@@ -3515,6 +4053,8 @@ If there is only one window, it is split regardless of this value.");
   defsubr (&Swindow_width);
   defsubr (&Swindow_hscroll);
   defsubr (&Sset_window_hscroll);
+  defsubr (&Swindow_redisplay_end_trigger);
+  defsubr (&Sset_window_redisplay_end_trigger);
   defsubr (&Swindow_edges);
   defsubr (&Scoordinates_in_window_p);
   defsubr (&Swindow_at);
@@ -3539,6 +4079,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);
@@ -3552,11 +4094,14 @@ 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 (&Scompare_window_configurations);
 }
 
+void
 keys_of_window ()
 {
   initial_define_key (control_x_map, '1', "delete-other-windows");