(Fwindow_end): Don't call temp_set_pt_both with
[bpt/emacs.git] / src / window.c
index 87807ac..dc01b2f 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985,86,87,93,94,95,96,1997 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,93,94,95,96,97,1998 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,15 +29,39 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "disptab.h"
 #include "keyboard.h"
+#include "dispextern.h"
 #include "blockinput.h"
+#include "intervals.h"
 
-Lisp_Object Qwindowp, Qwindow_live_p;
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif /* HAVE_X_WINDOWS */
 
-Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
-Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
+#ifndef max
+#define max(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+
+Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
+extern Lisp_Object Qheight, Qwidth;
+
+static struct window *decode_window P_ ((Lisp_Object));
+static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
+static int count_windows P_ ((struct window *));
+static int get_leaf_windows P_ ((struct window *, struct window **, int));
+static void window_scroll P_ ((Lisp_Object, int, int, int));
+static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
+static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
+static int window_min_size_1 P_ ((struct window *, int));
+static int window_min_size P_ ((struct window *, int, int, int *));
+static void size_window P_ ((Lisp_Object, int, int, int));
+static void foreach_window_1 P_ ((struct window *, void (*fn) (), int, int,
+                                 int, int));
+static void freeze_window_start P_ ((struct window *, int));
+static int window_fixed_size_p P_ ((struct window *, int, int));
+static void enlarge_window P_ ((Lisp_Object, int, int));
 
-void delete_all_subwindows ();
-static struct window *decode_window();
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -49,79 +73,102 @@ static struct window *decode_window();
 
 Lisp_Object selected_window;
 
-/* The minibuffer window of the selected frame.
-   Note that you cannot test for minibufferness of an arbitrary window
-   by comparing against this; but you can test for minibufferness of
+/* The mini-buffer window of the selected frame.
+   Note that you cannot test for mini-bufferness of an arbitrary window
+   by comparing against this; but you can test for mini-bufferness of
    the selected window.  */
+
 Lisp_Object minibuf_window;
 
 /* Non-nil means it is the window for C-M-v to scroll
-   when the minibuffer is selected.  */
+   when the mini-buffer is selected.  */
+
 Lisp_Object Vminibuf_scroll_window;
 
 /* Non-nil means this is the buffer whose window C-M-v should scroll.  */
+
 Lisp_Object Vother_window_scroll_buffer;
 
 /* Non-nil means it's function to call to display temp buffers.  */
+
 Lisp_Object Vtemp_buffer_show_function;
 
 /* If a window gets smaller than either of these, it is removed. */
+
 int window_min_height;
 int window_min_width;
 
 /* Nonzero implies Fdisplay_buffer should create windows. */
+
 int pop_up_windows;
 
 /* Nonzero implies make new frames for Fdisplay_buffer.  */
+
 int pop_up_frames;
 
 /* Non-nil means use this function instead of default */
+
 Lisp_Object Vpop_up_frame_function;
 
 /* Function to call to handle Fdisplay_buffer.  */
+
 Lisp_Object Vdisplay_buffer_function;
 
 /* List of buffer *names* for buffers that should have their own frames.  */
+
 Lisp_Object Vspecial_display_buffer_names;
 
 /* List of regexps for buffer names that should have their own frames.  */
+
 Lisp_Object Vspecial_display_regexps;
 
 /* Function to pop up a special frame.  */
+
 Lisp_Object Vspecial_display_function;
 
 /* List of buffer *names* for buffers to appear in selected window.  */
+
 Lisp_Object Vsame_window_buffer_names;
 
 /* List of regexps for buffer names to appear in selected window.  */
+
 Lisp_Object Vsame_window_regexps;
 
 /* Hook run at end of temp_output_buffer_show.  */
+
 Lisp_Object Qtemp_buffer_show_hook;
 
 /* Fdisplay_buffer always splits the largest window
    if that window is more than this high.  */
+
 int split_height_threshold;
 
 /* Number of lines of continuity in scrolling by screenfuls.  */
+
 int next_screen_context_lines;
 
 /* Incremented for each window created.  */
+
 static int sequence_number;
 
 /* Nonzero after init_window_once has finished.  */
+
 static int window_initialized;
 
 /* Hook to run when window config changes.  */
+
 Lisp_Object Qwindow_configuration_change_hook;
 Lisp_Object Vwindow_configuration_change_hook;
 
 /* Nonzero means scroll commands try to put point
    at the same screen height as previously.  */
-static int scroll_preserve_screen_position;
 
+Lisp_Object Vscroll_preserve_screen_position;
+
+#if 0 /* This isn't used anywhere.  */
 /* Nonzero means we can split a frame even if it is "unsplittable".  */
 static int inhibit_frame_unsplittable;
+#endif /* 0 */
 
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
@@ -157,22 +204,34 @@ make_window ()
   for (i = 0; i < VECSIZE (struct window); i++)
     vec->contents[i] = Qnil;
   vec->size = VECSIZE (struct window);
-  p = (struct window *)vec;
+  p = (struct window *) vec;
   XSETFASTINT (p->sequence_number, ++sequence_number);
   XSETFASTINT (p->left, 0);
   XSETFASTINT (p->top, 0);
   XSETFASTINT (p->height, 0);
   XSETFASTINT (p->width, 0);
   XSETFASTINT (p->hscroll, 0);
-  XSETFASTINT (p->last_point_x, 0);
-  XSETFASTINT (p->last_point_y, 0);
+  p->orig_top = p->orig_height = Qnil;
   p->start = Fmake_marker ();
   p->pointm = Fmake_marker ();
   XSETFASTINT (p->use_time, 0);
   p->frame = Qnil;
   p->display_table = Qnil;
   p->dedicated = Qnil;
+  p->pseudo_window_p = 0;
+  bzero (&p->cursor, sizeof (p->cursor));
+  bzero (&p->last_cursor, sizeof (p->last_cursor));
+  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
+  p->desired_matrix = p->current_matrix = 0;
+  p->phys_cursor_type = -1;
+  p->must_be_updated_p = 0;
+  XSETFASTINT (p->window_end_vpos, 0);
+  XSETFASTINT (p->window_end_pos, 0);
+  p->window_end_valid = Qnil;
+  p->vscroll = 0;
   XSETWINDOW (val, p);
+  XSETFASTINT (p->last_point, 0);
+  p->frozen_window_start_p = 0;
   return val;
 }
 
@@ -191,10 +250,8 @@ used by that frame.")
     Lisp_Object frame;
 {
   if (NILP (frame))
-    XSETFRAME (frame, selected_frame);
-  else
-    CHECK_LIVE_FRAME (frame, 0);
-
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 0);
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
 
@@ -216,12 +273,10 @@ POS defaults to point; WINDOW, to the selected window.")
      Lisp_Object pos, window;
 {
   register struct window *w;
-  register int top;
-  register int height;
   register int posint;
   register struct buffer *buf;
-  struct position posval;
-  int hscroll;
+  struct text_pos top;
+  Lisp_Object in_window;
 
   if (NILP (pos))
     posint = PT;
@@ -232,51 +287,35 @@ POS defaults to point; WINDOW, to the selected window.")
     }
 
   w = decode_window (window);
-  top = marker_position (w->start);
-  hscroll = XINT (w->hscroll);
-
-  if (posint < top)
-    return Qnil;
-
-  height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
-
   buf = XBUFFER (w->buffer);
-  if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
-      && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf))
-    {
-      /* If frame is up to date,
-        use the info recorded about how much text fit on it. */
-      if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos)
-         || (XFASTINT (w->window_end_vpos) < height))
-       return Qt;
-      return Qnil;
-    }
+  SET_TEXT_POS_FROM_MARKER (top, w->start);
+
+  /* If position above window, it's not visible.  */
+  if (posint < CHARPOS (top))
+    in_window = Qnil;
+  else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
+      && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
+      && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
+    /* If frame is up to date, and POSINT is < window end pos, use
+       that info.  This doesn't work for POSINT == end pos, because
+       the window end pos is actually the position _after_ the last
+       char in the window.  */
+    in_window = Qt;
+  else if (posint > BUF_ZV (buf))
+    in_window = Qnil;
+  else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
+    /* If window start is out of range, do something reasonable.  */
+    in_window = Qnil;
   else
     {
-      if (posint > BUF_ZV (buf))
-       return Qnil;
-
-      /* w->start can be out of range.  If it is, do something reasonable.  */
-      if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
-       return Qnil;
-
-      /* If that info is not correct, calculate afresh */
-      /* 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, - (1 << (BITS_PER_SHORT - 1)),
-                               window_internal_width (w) - 1,
-                               hscroll, 0, w);
-
-      return posval.vpos < height ? Qt : Qnil;
+      struct it it;
+      start_display (&it, w, top);
+      move_it_to (&it, posint, 0, it.last_visible_y, -1,
+                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+      in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
     }
+
+  return in_window;
 }
 \f
 static struct window *
@@ -337,7 +376,8 @@ NCOL should be zero or positive.")
   if (XINT (ncol) < 0) XSETFASTINT (ncol, 0);
   w = decode_window (window);
   if (XINT (w->hscroll) != XINT (ncol))
-    XBUFFER (w->buffer)->clip_changed = 1; /* Prevent redisplay shortcuts */
+    /* Prevent redisplay shortcuts */
+    XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
   w->hscroll = ncol;
   return ncol;
 }
@@ -388,7 +428,7 @@ and BOTTOM is one more than the bottommost row used by WINDOW\n\
                         Qnil))));
 }
 
-/* Test if the character at column *x, row *y is within window *w.
+/* Test if the character at column *X, row *Y is within window W.
    If it is not, return 0;
    if it is in the window's text area,
       set *x and *y to its location relative to the upper left corner
@@ -396,37 +436,77 @@ and BOTTOM is one more than the bottommost row used by WINDOW\n\
       return 1;
    if it is on the window's modeline, return 2;
    if it is on the border between the window and its right sibling,
-      return 3.  */
+      return 3.
+   if it is on the window's top line, return 4;
+   if it is in the bitmap area to the left/right of the window,
+   return 5 or 6, and convert *X and *Y to window-relative corrdinates.
+
+   X and Y are frame relative pixel coordinates.  */
+
 static int
 coordinates_in_window (w, x, y)
      register struct window *w;
      register int *x, *y;
 {
-  register int left = XINT (w->left);
-  register int 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 >= right_edge
-      || *y < top  || *y >= top  + window_height)
-    return 0;
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int left_x, right_x, top_y, bottom_y;
+  int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
 
-  if (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;
+  if (w->pseudo_window_p)
+    {
+      left_x = 0;
+      right_x = XFASTINT (w->width) * CANON_Y_UNIT (f);
+      top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
+      bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
+    }
+  else
+    {
+      left_x = WINDOW_DISPLAY_LEFT_EDGE_PIXEL_X (w);
+      right_x = WINDOW_DISPLAY_RIGHT_EDGE_PIXEL_X (w);
+      top_y = WINDOW_DISPLAY_TOP_EDGE_PIXEL_Y (w);
+      bottom_y = WINDOW_DISPLAY_BOTTOM_EDGE_PIXEL_Y (w);
+    }
 
-  *x -= WINDOW_LEFT_MARGIN (w);
-  *y -= top;
-  return 1;
+  if (*y < top_y
+      || *y >= bottom_y
+      || *x < (left_x
+              - flags_area_width
+              - (FRAME_LEFT_SCROLL_BAR_WIDTH (f)
+                 * CANON_X_UNIT (f)))
+      || *x > right_x + flags_area_width)
+    /* Completely outside anything interesting.  */
+    return 0;
+  else if (WINDOW_WANTS_MODELINE_P (w)
+          && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+    /* On the mode line.  */
+    return 2;
+  else if (WINDOW_WANTS_HEADER_LINE_P (w)
+          && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+    /* On the top line.  */
+    return 4;
+  else if (*x < left_x || *x >= right_x)
+    {
+      /* Other lines than the mode line don't include flags areas and
+        scroll bars on the left.  */
+      
+      /* Convert X and Y to window-relative pixel coordinates.  */
+      *x -= left_x;
+      *y -= top_y;
+      return *x < left_x ? 5 : 6;
+    }
+  else if (!w->pseudo_window_p
+          && !WINDOW_RIGHTMOST_P (w)
+          && *x >= right_x - CANON_X_UNIT (f))
+    /* On the border on the right side of the window?  Assume that
+       this area begins at RIGHT_X minus a canonical char width.  */
+    return 3;
+  else
+    {
+      /* Convert X and Y to window-relative pixel coordinates.  */
+      *x -= left_x;
+      *y -= top_y;
+      return 1;
+    }
 }
 
 DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
@@ -439,25 +519,42 @@ frame.\n\
 If COORDINATES are in the text portion of WINDOW,\n\
    the coordinates relative to the window are returned.\n\
 If they are in the mode line of WINDOW, `mode-line' is returned.\n\
+If they are in the top mode line of WINDOW, `header-line' is returned.\n\
+If they are in the bitmap-area to the left of the window,\n\
+   `left-bitmap-area' is returned, if they are in the area on the right of\n\
+   the window, `right-bitmap-area' is returned.\n\
 If they are on the border between WINDOW and its right sibling,\n\
    `vertical-line' is returned.")
   (coordinates, window)
      register Lisp_Object coordinates, window;
 {
+  struct window *w;
+  struct frame *f;
   int x, y;
+  Lisp_Object lx, ly;
 
   CHECK_LIVE_WINDOW (window, 0);
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
   CHECK_CONS (coordinates, 1);
-  x = XINT (Fcar (coordinates));
-  y = XINT (Fcdr (coordinates));
-
-  switch (coordinates_in_window (XWINDOW (window), &x, &y))
+  lx = Fcar (coordinates);
+  ly = Fcdr (coordinates);
+  CHECK_NUMBER_OR_FLOAT (lx, 1);
+  CHECK_NUMBER_OR_FLOAT (ly, 1);
+  x = PIXEL_X_FROM_CANON_X (f, lx);
+  y = PIXEL_Y_FROM_CANON_Y (f, ly);
+
+  switch (coordinates_in_window (w, &x, &y))
     {
     case 0:                    /* NOT in window at all. */
       return Qnil;
 
     case 1:                    /* In text part of window. */
-      return Fcons (make_number (x), make_number (y));
+      /* X and Y are now window relative pixel coordinates.
+        Convert them to canonical char units before returning
+        them.  */
+      return Fcons (CANON_X_FROM_PIXEL_X (f, x), 
+                   CANON_Y_FROM_PIXEL_Y (f, y));
 
     case 2:                    /* In mode line of window. */
       return Qmode_line;
@@ -465,29 +562,42 @@ If they are on the border between WINDOW and its right sibling,\n\
     case 3:                    /* On right border of window.  */
       return Qvertical_line;
 
+    case 4:
+      return Qheader_line;
+
+    case 5:
+      return Qleft_bitmap_area;
+      
+    case 6:
+      return Qright_bitmap_area;
+
     default:
       abort ();
     }
 }
 
-/* Find the window containing column x, row y, and return it as a
-   Lisp_Object.  If x, y is on the window's modeline, set *part
-   to 1; if it is on the separating line between the window and its
-   right sibling, set it to 2; otherwise set it to 0.  If there is no
-   window under x, y return nil and leave *part unmodified.  */
+/* Find the window containing frame-relative pixel position X/Y and
+   return it as a Lisp_Object.  If X, Y is on the window's modeline,
+   set *PART to 1; if it is on the separating line between the window
+   and its right sibling, set it to 2; otherwise set it to 0.  If
+   there is no window under X, Y return nil and leave *PART
+   unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.  */
+
 Lisp_Object
-window_from_coordinates (frame, x, y, part)
+window_from_coordinates (frame, x, y, part, tool_bar_p)
      FRAME_PTR frame;
      int x, y;
      int *part;
+     int tool_bar_p;
 {
   register Lisp_Object tem, first;
+  int found;
 
   tem = first = FRAME_SELECTED_WINDOW (frame);
 
   do
     {
-      int found = coordinates_in_window (XWINDOW (tem), &x, &y);
+      found = coordinates_in_window (XWINDOW (tem), &x, &y);
 
       if (found)
        {
@@ -497,7 +607,17 @@ window_from_coordinates (frame, x, y, part)
 
       tem = Fnext_window (tem, Qt, Qlambda);
     }
-  while (! EQ (tem, first));
+  while (!EQ (tem, first));
+
+  /* See if it's in the tool bar window, if a tool bar exists.  */
+  if (tool_bar_p
+      && WINDOWP (frame->tool_bar_window)
+      && XFASTINT (XWINDOW (frame->tool_bar_window)->height)
+      && coordinates_in_window (XWINDOW (frame->tool_bar_window), &x, &y))
+    {
+      *part = 0;
+      return frame->tool_bar_window;
+    }
 
   return Qnil;
 }
@@ -511,17 +631,21 @@ column 0.")
       Lisp_Object x, y, frame;
 {
   int part;
+  struct frame *f;
 
   if (NILP (frame))
-    XSETFRAME (frame, selected_frame);
-  else
-    CHECK_LIVE_FRAME (frame, 2);
-  CHECK_NUMBER (x, 0);
-  CHECK_NUMBER (y, 1);
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 2);
+  f = XFRAME (frame);
+
+  /* Check that arguments are integers or floats.  */
+  CHECK_NUMBER_OR_FLOAT (x, 0);
+  CHECK_NUMBER_OR_FLOAT (y, 1);
 
-  return window_from_coordinates (XFRAME (frame),
-                                 XINT (x), XINT (y),
-                                 &part);
+  return window_from_coordinates (f, 
+                                 PIXEL_X_FROM_CANON_X (f, x),
+                                 PIXEL_Y_FROM_CANON_Y (f, y),
+                                 &part, 0);
 }
 
 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
@@ -565,13 +689,15 @@ have been if redisplay had finished, do this:\n\
       (vertical-motion (1- (window-height window)) window)\n\
       (point))")  */
 
-DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
+DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
   "Return position at which display currently ends in WINDOW.\n\
 This is updated by redisplay, when it runs to completion.\n\
 Simply changing the buffer text or setting `window-start'\n\
-does not update this value.")
-  (window)
-     Lisp_Object window;
+does not update this value.\n\
+If UP-TO-DATE is non-nil, compute the up-to-date position\n\
+if it isn't already recorded.")
+  (window, update)
+     Lisp_Object window, update;
 {
   Lisp_Object value;
   struct window *w = decode_window (window);
@@ -589,8 +715,33 @@ does not update this value.")
     return Qnil;
 #endif
 
-  XSETINT (value,
-          BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+  if (! NILP (update)
+      && ! (! NILP (w->window_end_valid)
+           && XFASTINT (w->last_modified) >= MODIFF))
+    {
+      int opoint = PT, opoint_byte = PT_BYTE;
+
+      /* In case W->start is out of the range, use something
+         reasonable.  This situation occured when loading a file with
+         `-l' containing a call to `rmail' with subsequent other
+         commands.  At the end, W->start happened to be BEG, while
+         rmail had already narrowed the buffer.  This leads to an
+         abort in temp_set_pt_both.  */
+      if (XMARKER (w->start)->charpos < BEGV)
+       TEMP_SET_PT_BOTH (BEGV, BEGV_BYTE);
+      else if (XMARKER (w->start)->charpos > ZV)
+       TEMP_SET_PT_BOTH (ZV, ZV_BYTE);
+      else
+       TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
+                         XMARKER (w->start)->bytepos);
+      
+      Fvertical_motion (make_number (window_internal_height (w)), Qnil);
+      XSETINT (value, PT);
+      TEMP_SET_PT_BOTH (opoint, opoint_byte);
+    }
+  else
+    XSETINT (value,
+            BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
 
   return value;
 }
@@ -603,11 +754,12 @@ DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
   register struct window *w = decode_window (window);
 
   CHECK_NUMBER_COERCE_MARKER (pos, 1);
-  if (w == XWINDOW (selected_window))
+  if (w == XWINDOW (selected_window)
+      && XBUFFER (w->buffer) == current_buffer)
     Fgoto_char (pos);
   else
     set_marker_restricted (w->pointm, pos, w->buffer);
-
+  
   return pos;
 }
 
@@ -631,6 +783,7 @@ from overriding motion of point in order to display at this exact start.")
   XSETFASTINT (w->last_overlay_modified, 0);
   if (!EQ (window, selected_window))
     windows_or_buffers_changed++;
+
   return pos;
 }
 
@@ -673,10 +826,10 @@ DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
   return decode_window (window)->display_table;
 }
 
-/* Get the display table for use currently on window W.
-   This is either W's display table or W's buffer's display table.
-   Ignore the specified tables if they are not valid;
-   if no valid table is specified, return 0.  */
+/* Get the display table for use on window W.  This is either W's
+   display table or W's buffer's display table.  Ignore the specified
+   tables if they are not valid; if no valid table is specified,
+   return 0.  */
 
 struct Lisp_Char_Table *
 window_display_table (w)
@@ -686,6 +839,9 @@ window_display_table (w)
   tem = w->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
+  if (NILP (w->buffer))
+    return 0;
+
   tem = XBUFFER (w->buffer)->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
@@ -701,7 +857,6 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
      register Lisp_Object window, table;
 {
   register struct window *w;
-  register Lisp_Object z;      /* Return value. */
 
   w = decode_window (window);
   w->display_table = table;
@@ -710,18 +865,20 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
 \f
 /* Record info on buffer window w is displaying
    when it is about to cease to display that buffer.  */
-static
+static void
 unshow_buffer (w)
      register struct window *w;
 {
   Lisp_Object buf;
+  struct buffer *b;
 
   buf = w->buffer;
-  if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
+  b = XBUFFER (buf);
+  if (b != XMARKER (w->pointm)->buffer)
     abort ();
 
-  if (w == XWINDOW (XBUFFER (buf)->last_selected_window))
-    XBUFFER (buf)->last_selected_window = Qnil;
+  if (w == XWINDOW (b->last_selected_window))
+    b->last_selected_window = Qnil;
 
 #if 0
   if (w == XWINDOW (selected_window)
@@ -736,20 +893,23 @@ unshow_buffer (w)
        selected window, while last_window_start reflects another
        window which was recently showing the same buffer.
        Some people might say that might be a good thing.  Let's see.  */
-    XBUFFER (buf)->last_window_start = marker_position (w->start);
+    b->last_window_start = marker_position (w->start);
 
   /* Point in the selected window's buffer
      is actually stored in that buffer, and the window's pointm isn't used.
      So don't clobber point in that buffer.  */
   if (! EQ (buf, XWINDOW (selected_window)->buffer))
-    BUF_PT (XBUFFER (buf))
-      = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
-                       marker_position (w->pointm),
-                       BUF_ZV (XBUFFER (buf)));
+    temp_set_point_both (b,
+                        clip_to_bounds (BUF_BEGV (b),
+                                        XMARKER (w->pointm)->charpos,
+                                        BUF_ZV (b)),
+                        clip_to_bounds (BUF_BEGV_BYTE (b),
+                                        marker_byte_position (w->pointm),
+                                        BUF_ZV_BYTE (b)));
 }
 
 /* Put replacement into the window structure in place of old. */
-static
+static void
 replace_window (old, replacement)
      Lisp_Object old, replacement;
 {
@@ -766,6 +926,19 @@ replace_window (old, replacement)
   p->top = o->top;
   p->width = o->width;
   p->height = o->height;
+  p->desired_matrix = p->current_matrix = 0;
+  p->vscroll = 0;
+  bzero (&p->cursor, sizeof (p->cursor));
+  bzero (&p->last_cursor, sizeof (p->last_cursor));
+  bzero (&p->phys_cursor, sizeof (p->phys_cursor));
+  p->phys_cursor_type = -1;
+  p->must_be_updated_p = 0;
+  p->pseudo_window_p = 0;
+  XSETFASTINT (p->window_end_vpos, 0);
+  XSETFASTINT (p->window_end_pos, 0);
+  p->window_end_valid = Qnil;
+  p->frozen_window_start_p = 0;
+  p->orig_top = p->orig_height = Qnil;
 
   p->next = tem = o->next;
   if (!NILP (tem))
@@ -803,12 +976,14 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   return Qnil;
 }
 
+void
 delete_window (window)
      register Lisp_Object window;
 {
   register Lisp_Object tem, parent, sib;
   register struct window *p;
   register struct window *par;
+  FRAME_PTR frame;
 
   /* Because this function is called by other C code on non-leaf
      windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
@@ -831,7 +1006,8 @@ delete_window (window)
   par = XWINDOW (parent);
 
   windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (p))) = 1;
+  frame = XFRAME (WINDOW_FRAME (p));
+  FRAME_WINDOW_SIZES_CHANGED (frame) = 1;
 
   /* Are we trying to delete any frame's selected window?  */
   {
@@ -877,6 +1053,11 @@ delete_window (window)
       unchain_marker (p->start);
     }
 
+  /* Free window glyph matrices.
+     It is sure that they are allocated again when ADJUST_GLYPHS
+     is called. */
+  free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (frame)));
+
   tem = p->next;
   if (!NILP (tem))
     XWINDOW (tem)->prev = p->prev;
@@ -930,6 +1111,9 @@ delete_window (window)
 
   /* Mark this window as deleted.  */
   p->buffer = p->hchild = p->vchild = Qnil;
+
+  /* Adjust glyph matrices. */
+  adjust_glyphs (frame);
 }
 \f
 
@@ -1042,7 +1226,7 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
                   If that happens, go back to the selected frame
                   so we can complete the cycle.  */
                if (EQ (tem, tem1))
-                 XSETFRAME (tem, selected_frame);
+                 tem = selected_frame;
              }
            tem = FRAME_ROOT_WINDOW (XFRAME (tem));
 
@@ -1061,6 +1245,8 @@ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
            window = XWINDOW (window)->vchild;
          else break;
        }
+
+      QUIT;
     }
   /* Which windows are acceptable?
      Exit the loop and accept this window if
@@ -1194,7 +1380,7 @@ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
                   If that happens, go back to the selected frame
                   so we can complete the cycle.  */
                if (EQ (tem, tem1))
-                 XSETFRAME (tem, selected_frame);
+                 tem = selected_frame;
              }
            /* If this frame has a minibuffer, find that window first,
               because it is conceptually the last window in that frame.  */
@@ -1281,7 +1467,8 @@ enum window_loop
   DELETE_OTHER_WINDOWS,                /* Arg is window not to delete */
   DELETE_BUFFER_WINDOWS,       /* Arg is buffer */
   GET_LARGEST_WINDOW,
-  UNSHOW_BUFFER                /* Arg is buffer */
+  UNSHOW_BUFFER,               /* Arg is buffer */
+  CHECK_ALL_WINDOWS
 };
 
 static Lisp_Object
@@ -1304,7 +1491,7 @@ window_loop (type, obj, mini, frames)
   if (FRAMEP (frames))
     frame = XFRAME (frames);
   else if (NILP (frames))
-    frame = selected_frame;
+    frame = SELECTED_FRAME ();
   else
     frame = 0;
   if (frame)
@@ -1324,7 +1511,7 @@ window_loop (type, obj, mini, frames)
   else if (frame)
     w = FRAME_SELECTED_WINDOW (frame);
   else
-    w = FRAME_SELECTED_WINDOW (selected_frame);
+    w = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
 
   /* Figure out the last window we're going to mess with.  Since
      Fnext_window, given the same options, is guaranteed to go in a
@@ -1338,8 +1525,6 @@ window_loop (type, obj, mini, frames)
   best_window = Qnil;
   for (;;)
     {
-      FRAME_PTR w_frame = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-
       /* Pick the next window now, since some operations will delete
         the current window.  */
       next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg);
@@ -1348,6 +1533,8 @@ 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)
          {
@@ -1415,7 +1602,8 @@ window_loop (type, obj, mini, frames)
                  if (NILP (XWINDOW (w)->parent))
                    {
                      Lisp_Object new_buffer;
-                     new_buffer = Fother_buffer (obj, Qnil);
+                     new_buffer = Fother_buffer (obj, Qnil,
+                                                 XWINDOW (w)->frame);
                      if (NILP (new_buffer))
                        new_buffer
                          = Fget_buffer_create (build_string ("*scratch*"));
@@ -1450,7 +1638,7 @@ window_loop (type, obj, mini, frames)
                /* Find another buffer to show in this window.  */
                Lisp_Object another_buffer;
                FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-               another_buffer = Fother_buffer (obj, Qnil);
+               another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
                if (NILP (another_buffer))
                  another_buffer
                    = Fget_buffer_create (build_string ("*scratch*"));
@@ -1489,6 +1677,12 @@ window_loop (type, obj, mini, frames)
                  }
              }
            break;
+
+           /* Check for a window that has a killed buffer.  */
+         case CHECK_ALL_WINDOWS:
+           if (! NILP (XWINDOW (w)->buffer)
+               && NILP (XBUFFER (XWINDOW (w)->buffer)->name))
+             abort ();
          }
 
       if (EQ (w, last_window))
@@ -1500,6 +1694,14 @@ window_loop (type, obj, mini, frames)
   return best_window;
 }
 
+/* Used for debugging.  Abort if any window has a dead buffer.  */
+
+void
+check_all_windows ()
+{
+  window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
+}
+
 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
   "Return the window least recently selected or used for display.\n\
 If optional argument FRAME is `visible', search all visible frames.\n\
@@ -1575,7 +1777,7 @@ value is reasonable when this function is called.")
   w = XWINDOW (window);
 
   startpos = marker_position (w->start);
-  top = XFASTINT (w->top) - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)));
+  top = XFASTINT (w->top) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME (w)));
 
   if (MINI_WINDOW_P (w) && top > 0)
     error ("Can't expand minibuffer to full frame");
@@ -1598,9 +1800,9 @@ value is reasonable when this function is called.")
         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_BYTE (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.  */
@@ -1608,6 +1810,7 @@ value is reasonable when this function is called.")
 
       set_buffer_internal (obuf);
     }
+
   return Qnil;
 }
 
@@ -1615,17 +1818,20 @@ DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
   1, 2, "bDelete windows on (buffer): ",
   "Delete all windows showing BUFFER.\n\
 Optional second argument FRAME controls which frames are affected.\n\
-If nil or omitted, delete all windows showing BUFFER in any frame.\n\
-If t, delete only windows showing BUFFER in the selected frame.\n\
-If `visible', delete all windows showing BUFFER in any visible frame.\n\
-If a frame, delete only windows showing BUFFER in that frame.")
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is nil, search all frames.\n\
+If FRAME is t, search only the selected frame.\n\
+If FRAME is a frame, search only that frame.")
   (buffer, frame)
      Lisp_Object buffer, frame;
 {
   /* FRAME uses t and nil to mean the opposite of what window_loop
      expects.  */
-  if (! FRAMEP (frame))
-    frame = NILP (frame) ? Qt : Qnil;
+  if (NILP (frame))
+    frame = Qt;
+  else if (EQ (frame, Qt))
+    frame = Qnil;
 
   if (!NILP (buffer))
     {
@@ -1633,6 +1839,7 @@ If a frame, delete only windows showing BUFFER in that frame.")
       CHECK_BUFFER (buffer, 0);
       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
     }
+  
   return Qnil;
 }
 
@@ -1666,9 +1873,9 @@ replace_buffer_in_all_windows (buffer)
      because it only considers frames on the current keyboard.
      So loop manually over frames, and handle each one.  */
   FOR_EACH_FRAME (tail, frame)
-    window_loop (UNSHOW_BUFFER, buffer, 0, frame);
+    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
 #else
-  window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
+  window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
 #endif
 }
 \f
@@ -1676,6 +1883,7 @@ replace_buffer_in_all_windows (buffer)
 
 /* The smallest acceptable dimensions for a window.  Anything smaller
    might crash Emacs.  */
+
 #define MIN_SAFE_WINDOW_WIDTH  (2)
 #define MIN_SAFE_WINDOW_HEIGHT (2)
 
@@ -1694,6 +1902,7 @@ check_min_window_sizes ()
 
 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
    minimum allowable size.  */
+
 void
 check_frame_size (frame, rows, cols)
      FRAME_PTR frame;
@@ -1707,8 +1916,9 @@ check_frame_size (frame, rows, cols)
     (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
      : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
      : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
-  if (FRAME_MENU_BAR_LINES (frame) > 0)
-    min_height += FRAME_MENU_BAR_LINES (frame);
+  
+  if (FRAME_TOP_MARGIN (frame) > 0)
+    min_height += FRAME_TOP_MARGIN (frame);
 
   if (*rows < min_height)
     *rows = min_height;
@@ -1716,142 +1926,427 @@ check_frame_size (frame, rows, cols)
     *cols = MIN_SAFE_WINDOW_WIDTH;
 }
 
-/* Normally the window is deleted if it gets too small.
-   nodelete nonzero means do not do this.
-   (The caller should check later and do so if appropriate)  */
 
-set_window_height (window, height, nodelete)
-     Lisp_Object window;
-     int height;
-     int nodelete;
+/* Value is non-zero if window W is fixed-size.  WIDTH_P non-zero means
+   check if W's width can be changed, otherwise check W's height.
+   CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
+   siblings, too.  If none of the siblings is resizable, WINDOW isn't
+   either.  */
+
+static int
+window_fixed_size_p (w, width_p, check_siblings_p)
+     struct window *w;
+     int width_p, check_siblings_p;
 {
-  register struct window *w = XWINDOW (window);
-  register struct window *c;
-  int oheight = XFASTINT (w->height);
-  int top, pos, lastbot, opos, lastobot;
-  Lisp_Object child;
+  int fixed_p;
+  struct window *c;
+  
+  if (!NILP (w->hchild))
+    {
+      c = XWINDOW (w->hchild);
+      
+      if (width_p)
+       {
+         /* A horiz. combination is fixed-width if all of if its
+            children are.  */
+         while (c && window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c == NULL;
+       }
+      else
+       {
+         /* A horiz. combination is fixed-height if one of if its
+            children is.  */
+         while (c && !window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c != NULL;
+       }
+    }
+  else if (!NILP (w->vchild))
+    {
+      c = XWINDOW (w->vchild);
+      
+      if (width_p)
+       {
+         /* A vert. combination is fixed-width if one of if its
+            children is.  */
+         while (c && !window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c != NULL;
+       }
+      else
+       {
+         /* A vert. combination is fixed-height if all of if its
+            children are.  */
+         while (c && window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c == NULL;
+       }
+    }
+  else if (BUFFERP (w->buffer))
+    {
+      if (w->height_fixed_p && !width_p)
+       fixed_p = 1;
+      else
+       {
+         struct buffer *old = current_buffer;
+         Lisp_Object val;
+      
+         current_buffer = XBUFFER (w->buffer);
+         val = find_symbol_value (Qwindow_size_fixed);
+         current_buffer = old;
+
+         fixed_p = 0;
+         if (!EQ (val, Qunbound))
+           {
+             fixed_p = !NILP (val);
+             
+             if (fixed_p
+                 && ((EQ (val, Qheight) && width_p)
+                     || (EQ (val, Qwidth) && !width_p)))
+               fixed_p = 0;
+           }
+       }
 
-  check_min_window_sizes ();
+      /* Can't tell if this one is resizable without looking at
+        siblings.  If all siblings are fixed-size this one is too.  */
+      if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
+       {
+         Lisp_Object child;
+         
+         for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
+           if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+             break;
 
-  if (!nodelete
-      && ! NILP (w->parent)
-      && height < window_min_height)
-    {
-      delete_window (window);
-      return;
+         if (NILP (child))
+           for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
+             if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+               break;
+
+         if (NILP (child))
+           fixed_p = 1;
+       }
     }
+  else
+    fixed_p = 1;
 
-  XSETFASTINT (w->last_modified, 0);
-  XSETFASTINT (w->last_overlay_modified, 0);
-  windows_or_buffers_changed++;
-  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+  return fixed_p;
+}
+  
 
-  XSETFASTINT (w->height, height);
+/* Return the minimum size of window W, not taking fixed-width windows
+   into account.  WIDTH_P non-zero means return the minimum width,
+   otherwise return the minimum height.  If W is a combination window,
+   compute the minimum size from the minimum sizes of W's children.  */
+
+static int
+window_min_size_1 (w, width_p)
+     struct window *w;
+     int width_p;
+{
+  struct window *c;
+  int size;
+  
   if (!NILP (w->hchild))
     {
-      for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+      c = XWINDOW (w->hchild);
+      size = 0;
+      
+      if (width_p)
+       {
+         /* The min width of a horizontal combination is
+            the sum of the min widths of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+      else
        {
-         XWINDOW (child)->top = w->top;
-         set_window_height (child, height, nodelete);
+         /* The min height a horizontal combination equals
+            the maximum of all min height of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
        }
     }
   else if (!NILP (w->vchild))
     {
-      lastbot = top = XFASTINT (w->top);
-      lastobot = 0;
-      for (child = w->vchild; !NILP (child); child = c->next)
+      c = XWINDOW (w->vchild);
+      size = 0;
+      
+      if (width_p)
        {
-         c = XWINDOW (child);
+         /* The min width of a vertical combination is
+            the maximum of the min widths of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+      else
+       {
+         /* The min height of a vertical combination equals
+            the sum of the min height of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+    }
+  else
+    {
+      if (width_p)
+       size = window_min_width;
+      else
+       {
+         if (MINI_WINDOW_P (w)
+             || (!WINDOW_WANTS_MODELINE_P (w)
+                 && !WINDOW_WANTS_HEADER_LINE_P (w)))
+           size = 1;
+         else
+           size = window_min_height;
+       }
+    }
 
-         opos = lastobot + XFASTINT (c->height);
+  return size;
+}
 
-         XSETFASTINT (c->top, lastbot);
 
-         pos = (((opos * height) << 1) + oheight) / (oheight << 1);
+/* Return the minimum size of window W, taking fixed-size windows into
+   account.  WIDTH_P non-zero means return the minimum width,
+   otherwise return the minimum height.  IGNORE_FIXED_P non-zero means
+   ignore if W is fixed-size.  Set *FIXED to 1 if W is fixed-size
+   unless FIXED is null.  */
 
-         /* Avoid confusion: inhibit deletion of child if becomes too small */
-         set_window_height (child, pos + top - lastbot, 1);
+static int
+window_min_size (w, width_p, ignore_fixed_p, fixed)
+     struct window *w;
+     int width_p, ignore_fixed_p, *fixed;
+{
+  int size, fixed_p;
 
-         /* Now advance child to next window,
-            and set lastbot if child was not just deleted.  */
-         lastbot = pos + top;
-         lastobot = opos;
-       }
-      /* Now delete any children that became too small.  */
-      if (!nodelete)
-       for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
-         {
-           set_window_height (child, XINT (XWINDOW (child)->height), 0);
-         }
-    }
+  if (ignore_fixed_p)
+    fixed_p = 0;
+  else
+    fixed_p = window_fixed_size_p (w, width_p, 1);
+  
+  if (fixed)
+    *fixed = fixed_p;
+  
+  if (fixed_p)
+    size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
+  else
+    size = window_min_size_1 (w, width_p);
+      
+  return size;
 }
 
-/* Recursively set width of WINDOW and its inferiors. */
 
-set_window_width (window, width, nodelete)
+/* Set WINDOW's height or width to SIZE.  WIDTH_P non-zero means set
+   WINDOW's width.  Resize WINDOW's children, if any, so that they
+   keep their proportionate size relative to WINDOW.  Propagate
+   WINDOW's top or left edge position to children.  Delete windows
+   that become too small unless NODELETE_P is non-zero.  */
+
+static void
+size_window (window, size, width_p, nodelete_p)
      Lisp_Object window;
-     int width;
-     int nodelete;
+     int size, width_p, nodelete_p;
 {
-  register struct window *w = XWINDOW (window);
-  register struct window *c;
-  int owidth = XFASTINT (w->width);
-  int left, pos, lastright, opos, lastoright;
-  Lisp_Object child;
+  struct window *w = XWINDOW (window);
+  struct window *c;
+  Lisp_Object child, *forward, *sideward;
+  int old_size, min_size;
 
-  if (!nodelete && width < window_min_width && !NILP (w->parent))
+  check_min_window_sizes ();
+  
+  /* If the window has been "too small" at one point,
+     don't delete it for being "too small" in the future.
+     Preserve it as long as that is at all possible.  */
+  if (width_p)
     {
-      delete_window (window);
-      return;
+      old_size = XFASTINT (w->width);
+      min_size = window_min_width;
+    }
+  else
+    {
+      old_size = XFASTINT (w->height);
+      min_size = window_min_height;
+    }
+  
+  if (old_size < window_min_width)
+    w->too_small_ok = Qt;
+
+  /* Maybe delete WINDOW if it's too small.  */
+  if (!nodelete_p && !NILP (w->parent))
+    {
+      int min_size;
+
+      if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
+       min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
+      else
+       min_size = width_p ? window_min_width : window_min_height;
+      
+      if (size < min_size)
+       {
+         delete_window (window);
+         return;
+       }
     }
 
+  /* Set redisplay hints.  */
   XSETFASTINT (w->last_modified, 0);
   XSETFASTINT (w->last_overlay_modified, 0);
   windows_or_buffers_changed++;
   FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
 
-  XSETFASTINT (w->width, width);
-  if (!NILP (w->vchild))
+  if (width_p)
     {
-      for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
+      sideward = &w->vchild;
+      forward = &w->hchild;
+      XSETFASTINT (w->width, size);
+    }
+  else
+    {
+      sideward = &w->hchild;
+      forward = &w->vchild;
+      XSETFASTINT (w->height, size);
+    }
+
+  if (!NILP (*sideward))
+    {
+      for (child = *sideward; !NILP (child); child = c->next)
        {
-         XWINDOW (child)->left = w->left;
-         set_window_width (child, width, nodelete);
+         c = XWINDOW (child);
+         if (width_p)
+           c->left = w->left;
+         else
+           c->top = w->top;
+         size_window (child, size, width_p, nodelete_p);
        }
     }
-  else if (!NILP (w->hchild))
+  else if (!NILP (*forward))
     {
-      lastright = left = XFASTINT (w->left);
-      lastoright = 0;
-      for (child = w->hchild; !NILP (child); child = c->next)
+      int fixed_size, each, extra, n;
+      int resize_fixed_p, nfixed;
+      int last_pos, first_pos, nchildren;
+
+      /* Determine the fixed-size portion of the this window, and the
+        number of child windows.  */
+      fixed_size = nchildren = nfixed = 0;
+      for (child = *forward; !NILP (child); child = c->next, ++nchildren)
        {
          c = XWINDOW (child);
+         if (window_fixed_size_p (c, width_p, 0))
+           {
+             fixed_size += (width_p
+                            ? XFASTINT (c->width) : XFASTINT (c->height));
+             ++nfixed;
+           }
+       }
 
-         opos = lastoright + XFASTINT (c->width);
-
-         XSETFASTINT (c->left, lastright);
-
-         pos = (((opos * width) << 1) + owidth) / (owidth << 1);
+      /* If the new size is smaller than fixed_size, or if there
+        aren't any resizable windows, allow resizing fixed-size
+        windows.  */
+      resize_fixed_p = nfixed == nchildren || size < fixed_size;
+
+      /* Compute how many lines/columns to add to each child.  The
+        value of extra takes care of rounding errors.  */
+      n = resize_fixed_p ? nchildren : nchildren - nfixed;
+      each = (size - old_size) / n;
+      extra = (size - old_size) - n * each;
+
+      /* Compute new children heights and edge positions.  */
+      first_pos = width_p ? XFASTINT (w->left) : XFASTINT (w->top);
+      last_pos = first_pos;
+      for (child = *forward; !NILP (child); child = c->next)
+       {
+         int new_size, old_size;
+         
+         c = XWINDOW (child);
+         old_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+         new_size = old_size;
 
-         /* Inhibit deletion for becoming too small */
-         set_window_width (child, pos + left - lastright, 1);
+         /* The top or left edge position of this child equals the
+            bottom or right edge of its predecessor.  */
+         if (width_p)
+           c->left = make_number (last_pos);
+         else
+           c->top = make_number (last_pos);
 
-         /* Now advance child to next window,
-            and set lastright if child was not just deleted.  */
-         lastright = pos + left, lastoright = opos;
+         /* If this child can be resized, do it.  */
+         if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
+           {
+             new_size = old_size + each + extra;
+             extra = 0;
+           }
+         
+         /* Set new height.  Note that size_window also propagates
+            edge positions to children, so it's not a no-op if we
+            didn't change the child's size.  */
+         size_window (child, new_size, width_p, 1);
+
+         /* Remember the bottom/right edge position of this child; it
+            will be used to set the top/left edge of the next child.  */
+         last_pos += new_size;
        }
-      /* Delete children that became too small */
-      if (!nodelete)
-       for (child = w->hchild; !NILP (child); child = XWINDOW (child)->next)
+
+      /* We should have covered the parent exactly with child windows.  */
+      xassert (size == last_pos - first_pos);
+      
+      /* Now delete any children that became too small.  */
+      if (!nodelete_p)
+       for (child = *forward; !NILP (child); child = c->next)
          {
-           set_window_width (child, XINT (XWINDOW (child)->width), 0);
+           int child_size;
+           c = XWINDOW (child);
+           child_size = width_p ? XFASTINT (c->width) : XFASTINT (c->height);
+           size_window (child, child_size, width_p, 0);
          }
     }
 }
-\f
-int window_select_count;
 
-Lisp_Object
+/* Set WINDOW's height to HEIGHT, and recursively change the height of
+   WINDOW's children.  NODELETE non-zero means don't delete windows
+   that become too small in the process.  (The caller should check
+   later and do so if appropriate.)  */
+
+void
+set_window_height (window, height, nodelete)
+     Lisp_Object window;
+     int height;
+     int nodelete;
+{
+  size_window (window, height, 0, nodelete);
+}
+
+
+/* Set WINDOW's width to WIDTH, and recursively change the width of
+   WINDOW's children.  NODELETE non-zero means don't delete windows
+   that become too small in the process.  (The caller should check
+   later and do so if appropriate.)  */
+
+void
+set_window_width (window, width, nodelete)
+     Lisp_Object window;
+     int width;
+     int nodelete;
+{
+  size_window (window, width, 1, nodelete);
+}
+
+\f
+int window_select_count;
+
+Lisp_Object
 Fset_window_buffer_unwind (obuf)
      Lisp_Object obuf;
 {
@@ -1859,51 +2354,38 @@ Fset_window_buffer_unwind (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.")
-  (window, buffer)
-     register Lisp_Object window, buffer;
-{
-  register Lisp_Object tem;
-  register struct window *w = decode_window (window);
-  int count = specpdl_ptr - specpdl;
-
-  buffer = Fget_buffer (buffer);
-  CHECK_BUFFER (buffer, 1);
-
-  if (NILP (XBUFFER (buffer)->name))
-    error ("Attempt to display deleted buffer");
 
-  tem = w->buffer;
-  if (NILP (tem))
-    error ("Window is deleted");
-  else if (! EQ (tem, Qt))     /* w->buffer is t when the window
-                                  is first being set up.  */
-    {
-      if (!NILP (w->dedicated) && !EQ (tem, buffer))
-       error ("Window is dedicated to `%s'",
-              XSTRING (XBUFFER (tem)->name)->data);
+/* Make WINDOW display BUFFER as its contents.  RUN_HOOKS_P non-zero
+   means it's allowed to run hooks.  See make_frame for a case where
+   it's not allowed.  */
 
-      unshow_buffer (w);
-    }
+void
+set_window_buffer (window, buffer, run_hooks_p)
+     Lisp_Object window, buffer;
+     int run_hooks_p;
+{
+  struct window *w = XWINDOW (window);
+  struct buffer *b = XBUFFER (buffer);
+  int count = specpdl_ptr - specpdl;
 
   w->buffer = buffer;
 
   if (EQ (window, selected_window))
-    XBUFFER (w->buffer)->last_selected_window = window;
-  if (INTEGERP (XBUFFER (buffer)->display_count))
-    XSETINT (XBUFFER (buffer)->display_count,
-            XINT (XBUFFER (buffer)->display_count) + 1);
+    b->last_selected_window = window;
+
+  /* Update time stamps of buffer display.  */
+  if (INTEGERP (b->display_count))
+    XSETINT (b->display_count, XINT (b->display_count) + 1);
+  b->display_time = Fcurrent_time ();
 
   XSETFASTINT (w->window_end_pos, 0);
+  XSETFASTINT (w->window_end_vpos, 0);
+  bzero (&w->last_cursor, sizeof w->last_cursor);
   w->window_end_valid = Qnil;
   XSETFASTINT (w->hscroll, 0);
-  Fset_marker (w->pointm,
-              make_number (BUF_PT (XBUFFER (buffer))),
-              buffer);
+  set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
   set_marker_restricted (w->start,
-                        make_number (XBUFFER (buffer)->last_window_start),
+                        make_number (b->last_window_start),
                         buffer);
   w->start_at_line_beg = Qnil;
   w->force_start = Qnil;
@@ -1924,28 +2406,75 @@ BUFFER can be a buffer or buffer name.")
       Fset_buffer (buffer);
     }
 
-  if (! NILP (Vwindow_scroll_functions))
-    run_hook_with_args_2 (Qwindow_scroll_functions, window,
-                         Fmarker_position (w->start));
+  /* Set left and right marginal area width from buffer.  */
+  Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
 
-  if (! NILP (Vwindow_configuration_change_hook)
-      && ! NILP (Vrun_hooks))
-    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+  if (run_hooks_p)
+    {
+      if (! NILP (Vwindow_scroll_functions))
+       run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                             Fmarker_position (w->start));
+
+      if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+    }
 
   unbind_to (count, Qnil);
+}
+
+
+DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0,
+  "Make WINDOW display BUFFER as its contents.\n\
+BUFFER can be a buffer or buffer name.")
+  (window, buffer)
+     register Lisp_Object window, buffer;
+{
+  register Lisp_Object tem;
+  register struct window *w = decode_window (window);
+
+  buffer = Fget_buffer (buffer);
+  CHECK_BUFFER (buffer, 1);
+
+  if (NILP (XBUFFER (buffer)->name))
+    error ("Attempt to display deleted buffer");
+
+  tem = w->buffer;
+  if (NILP (tem))
+    error ("Window is deleted");
+  else if (! EQ (tem, Qt))     /* w->buffer is t when the window
+                                  is first being set up.  */
+    {
+      if (!NILP (w->dedicated) && !EQ (tem, buffer))
+       error ("Window is dedicated to `%s'",
+              XSTRING (XBUFFER (tem)->name)->data);
+
+      unshow_buffer (w);
+    }
 
+  set_window_buffer (window, buffer, 1);
   return Qnil;
 }
 
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
   "Select WINDOW.  Most editing will apply to WINDOW's buffer.\n\
-The main editor command loop selects the buffer of the selected window\n\
-before each command.")
+If WINDOW is not already selected, also make WINDOW's buffer current.\n\
+Note that the main editor command loop\n\
+selects the buffer of the selected window before each command.")
   (window)
      register Lisp_Object window;
+{
+  return select_window_1 (window, 1);
+}
+\f
+static Lisp_Object
+select_window_1 (window, recordflag)
+     register Lisp_Object window;
+     int recordflag;
 {
   register struct window *w;
   register struct window *ow = XWINDOW (selected_window);
+  struct frame *sf;
 
   CHECK_LIVE_WINDOW (window, 0);
 
@@ -1958,11 +2487,14 @@ before each command.")
   if (EQ (window, selected_window))
     return window;
 
-  Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
-              ow->buffer);
+  if (! NILP (ow->buffer))
+    set_marker_both (ow->pointm, ow->buffer,
+                    BUF_PT (XBUFFER (ow->buffer)),
+                    BUF_PT_BYTE (XBUFFER (ow->buffer)));
 
   selected_window = window;
-  if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
+  sf = SELECTED_FRAME ();
+  if (XFRAME (WINDOW_FRAME (w)) != sf)
     {
       XFRAME (WINDOW_FRAME (w))->selected_window = window;
       /* Use this rather than Fhandle_switch_frame
@@ -1972,9 +2504,10 @@ before each command.")
       Fselect_frame (WINDOW_FRAME (w), Qnil);
     }
   else
-    selected_frame->selected_window = window;
+    sf->selected_window = window;
 
-  record_buffer (w->buffer);
+  if (recordflag)
+    record_buffer (w->buffer);
   Fset_buffer (w->buffer);
 
   XBUFFER (w->buffer)->last_selected_window = window;
@@ -1997,7 +2530,7 @@ before each command.")
   windows_or_buffers_changed++;
   return window;
 }
-
+\f
 /* Deiconify the frame containing the window WINDOW,
    unless it is the selected frame;
    then return WINDOW.
@@ -2012,15 +2545,19 @@ static Lisp_Object
 display_buffer_1 (window)
      Lisp_Object window;
 {
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
+  Lisp_Object frame = XWINDOW (window)->frame;
+  FRAME_PTR f = XFRAME (frame);
+  
   FRAME_SAMPLE_VISIBILITY (f);
-  if (f != selected_frame)
+  
+  if (!EQ (frame, selected_frame))
     {
       if (FRAME_ICONIFIED_P (f))
-       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
+       Fmake_frame_visible (frame);
       else if (FRAME_VISIBLE_P (f))
-       Fraise_frame (WINDOW_FRAME (XWINDOW (window)));
+       Fraise_frame (frame);
     }
+  
   return window;
 }
 
@@ -2053,7 +2590,7 @@ See `special-display-buffer-names', and `special-display-regexps'.")
       else if (CONSP (car)
               && STRINGP (XCAR (car))
               && fast_string_match (XCAR (car), buffer_name) >= 0)
-       return XCDR (tem);
+       return XCDR (car);
     }
   return Qnil;
 }  
@@ -2090,8 +2627,9 @@ See `same-window-buffer-names' and `same-window-regexps'.")
   return Qnil;
 }
 
-DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
-     "BDisplay buffer: \nP",   /* Use B so the default is (other-buffer).  */
+   /* 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\
@@ -2102,12 +2640,23 @@ Returns the window displaying BUFFER.\n\
 \n\
 The variables `special-display-buffer-names', `special-display-regexps',\n\
 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
-buffer names are handled.")
-  (buffer, not_this_window)
-     register Lisp_Object buffer, not_this_window;
+buffer names are handled.\n\
+\n\
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is t, search all frames.\n\
+If FRAME is a frame, search only that frame.\n\
+If FRAME is nil, search only the selected frame\n\
+ (actually the last nonminibuffer frame),\n\
+ unless `pop-up-frames' is non-nil,\n\
+ which means search visible and iconified frames.")
+  (buffer, not_this_window, frame)
+     register Lisp_Object buffer, not_this_window, frame;
 {
-  register Lisp_Object window, tem;
+  register Lisp_Object window, tem, swp;
+  struct frame *f;
 
+  swp = Qnil;
   buffer = Fget_buffer (buffer);
   CHECK_BUFFER (buffer, 0);
 
@@ -2122,8 +2671,8 @@ buffer names are handled.")
      in the selected window.  */
   if (NILP (not_this_window))
     {
-      tem = Fsame_window_p (XBUFFER (buffer)->name);
-      if (!NILP (tem))
+      swp = Fsame_window_p (XBUFFER (buffer)->name);
+      if (!NILP (swp) && !no_switch_window (selected_window))
        {
          Fswitch_to_buffer (buffer, Qnil);
          return display_buffer_1 (selected_window);
@@ -2133,7 +2682,9 @@ buffer names are handled.")
   /* If pop_up_frames,
      look for a window showing BUFFER on any visible or iconified frame.
      Otherwise search only the current frame.  */
-  if (pop_up_frames || last_nonminibuf_frame == 0)
+  if (! NILP (frame))
+    tem = frame;
+  else if (pop_up_frames || last_nonminibuf_frame == 0)
     XSETFASTINT (tem, 0);
   else
     XSETFRAME (tem, last_nonminibuf_frame);
@@ -2145,7 +2696,7 @@ buffer names are handled.")
     }
 
   /* Certain buffer names get special handling.  */
-  if (!NILP (Vspecial_display_function))
+  if (!NILP (Vspecial_display_function) && NILP (swp))
     {
       tem = Fspecial_display_p (XBUFFER (buffer)->name);
       if (EQ (tem, Qt))
@@ -2163,17 +2714,17 @@ buffer names are handled.")
       return display_buffer_1 (window);
     }
 
+  f = SELECTED_FRAME ();
   if (pop_up_windows
-      || FRAME_MINIBUF_ONLY_P (selected_frame)
+      || FRAME_MINIBUF_ONLY_P (f)
       /* If the current frame is a special display frame,
         don't try to reuse its windows.  */
-      || !NILP (XWINDOW (FRAME_ROOT_WINDOW (selected_frame))->dedicated)
-      )
+      || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
     {
       Lisp_Object frames;
 
       frames = Qnil;
-      if (FRAME_MINIBUF_ONLY_P (selected_frame))
+      if (FRAME_MINIBUF_ONLY_P (f))
        XSETFRAME (frames, last_nonminibuf_frame);
       /* Don't try to create a window if would get an error */
       if (split_height_threshold < window_min_height << 1)
@@ -2185,8 +2736,7 @@ buffer names are handled.")
 
       /* If the frame we would try to split cannot be split,
         try other frames.  */
-      if (FRAME_NO_SPLIT_P (NILP (frames) ? selected_frame
-                           : last_nonminibuf_frame))
+      if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
        {
          /* Try visible frames first.  */
          window = Fget_largest_window (Qvisible);
@@ -2254,14 +2804,9 @@ buffer names are handled.")
            {
              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
-                                    - XFASTINT (XWINDOW (upper)->height)),
-                                   0);
-             selected_window = old_selected_window;
+             enlarge_window (upper,
+                             total / 2 - XFASTINT (XWINDOW (upper)->height),
+                             0);
            }
        }
     }
@@ -2287,24 +2832,25 @@ temp_output_buffer_show (buf)
   BEGV = BEG;
   ZV = Z;
   SET_PT (BEG);
-  XBUFFER (buf)->clip_changed = 1;
+  XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
   set_buffer_internal (old);
 
   if (!EQ (Vtemp_buffer_show_function, Qnil))
     call1 (Vtemp_buffer_show_function, buf);
   else
     {
-      window = Fdisplay_buffer (buf, Qnil);
+      window = Fdisplay_buffer (buf, Qnil, Qnil);
 
-      if (XFRAME (XWINDOW (window)->frame) != selected_frame)
+      if (!EQ (XWINDOW (window)->frame, selected_frame))
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
       Vminibuf_scroll_window = window;
       w = XWINDOW (window);
       XSETFASTINT (w->hscroll, 0);
-      set_marker_restricted (w->start, make_number (1), buf);
-      set_marker_restricted (w->pointm, make_number (1), buf);
+      set_marker_restricted_both (w->start, buf, 1, 1);
+      set_marker_restricted_both (w->pointm, buf, 1, 1);
 
-      /* Run temp-buffer-show-hook, with the chosen window selected.  */
+      /* Run temp-buffer-show-hook, with the chosen window selected
+        and it sbuffer current.  */
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object tem;
@@ -2315,13 +2861,15 @@ temp_output_buffer_show (buf)
              if (!NILP (tem))
                {
                  int count = specpdl_ptr - specpdl;
+                 Lisp_Object prev_window;
+                 prev_window = selected_window;
 
                  /* Select the window that was chosen, for running the hook.  */
-                 record_unwind_protect (Fset_window_configuration,
-                                        Fcurrent_window_configuration (Qnil));
-
-                 Fselect_window (window);
+                 record_unwind_protect (Fselect_window, prev_window);
+                 select_window_1 (window, 0);
+                 Fset_buffer (w->buffer);
                  call1 (Vrun_hooks, Qtemp_buffer_show_hook);
+                 select_window_1 (prev_window, 0);
                  unbind_to (count, Qnil);
                }
            }
@@ -2329,7 +2877,7 @@ temp_output_buffer_show (buf)
     }
 }
 \f
-static
+static void
 make_dummy_parent (window)
      Lisp_Object window;
 {
@@ -2366,7 +2914,8 @@ DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
   "Split WINDOW, putting SIZE lines in the first of the pair.\n\
 WINDOW defaults to selected one and SIZE to half its size.\n\
 If optional third arg HORFLAG is non-nil, split side by side\n\
-and put SIZE columns in the first of the pair.")
+and put SIZE columns in the first of the pair.  In that case,\n\
+SIZE includes that window's scroll bar, or the divider column to its right.")
   (window, size, horflag)
      Lisp_Object window, size, horflag;
 {
@@ -2387,8 +2936,10 @@ and put SIZE columns in the first of the pair.")
     {
       if (!NILP (horflag))
        /* Calculate the size of the left-hand window, by dividing
-          the usable space in columns by two. */
-       size_int = XFASTINT (o->width) >> 1;
+          the usable space in columns by two.
+          We round up, since the left-hand window may include
+          a dividing line, while the right-hand may not.  */
+       size_int = (XFASTINT (o->width) + 1) >> 1;
       else
        size_int = XFASTINT (o->height) >> 1;
     }
@@ -2400,6 +2951,8 @@ and put SIZE columns in the first of the pair.")
 
   if (MINI_WINDOW_P (o))
     error ("Attempt to split minibuffer window");
+  else if (window_fixed_size_p (o, !NILP (horflag), 0))
+    error ("Attempt to split fixed-size window");
 
   check_min_window_sizes ();
 
@@ -2452,6 +3005,8 @@ and put SIZE columns in the first of the pair.")
   o->next = new;
   p->parent = o->parent;
   p->buffer = Qt;
+  p->window_end_valid = Qnil;
+  bzero (&p->last_cursor, sizeof p->last_cursor);
 
   /* Apportion the available frame space among the two new windows */
 
@@ -2472,8 +3027,9 @@ and put SIZE columns in the first of the pair.")
       XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
     }
 
+  /* Adjust glyph matrices.  */
+  adjust_glyphs (fo);
   Fset_window_buffer (new, o->buffer);
-
   return new;
 }
 \f
@@ -2484,7 +3040,7 @@ From program, optional second arg non-nil means grow sideways ARG columns.")
      register Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg, 0);
-  change_window_height (XINT (arg), !NILP (side));
+  enlarge_window (selected_window, XINT (arg), !NILP (side));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -2499,7 +3055,7 @@ From program, optional second arg non-nil means shrink sideways arg columns.")
      register Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg, 0);
-  change_window_height (-XINT (arg), !NILP (side));
+  enlarge_window (selected_window, -XINT (arg), !NILP (side));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -2523,52 +3079,58 @@ window_width (window)
   return XFASTINT (p->width);
 }
 
-#define MINSIZE(w)                                             \
-  (widthflag                                                   \
-   ? window_min_width                                          \
-   : (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))
-
+       
 #define CURBEG(w) \
   *(widthflag ? (int *) &(XWINDOW (w)->left) : (int *) &(XWINDOW (w)->top))
 
 #define CURSIZE(w) \
   *(widthflag ? (int *) &(XWINDOW (w)->width) : (int *) &(XWINDOW (w)->height))
 
-/* Unlike set_window_height, this function
-   also changes the heights of the siblings so as to
-   keep everything consistent. */
 
-change_window_height (delta, widthflag)
-     register int delta;
-     int widthflag;
-{
-  register Lisp_Object parent;
-  Lisp_Object window;
-  register struct window *p;
-  int *sizep;
-  int (*sizefun) () = widthflag ? window_width : window_height;
-  register int (*setsizefun) () = (widthflag
-                                  ? set_window_width
-                                  : set_window_height);
-  int maximum;
-  Lisp_Object next, prev;
+/* Enlarge selected_window by DELTA.  WIDTHFLAG non-zero means
+   increase its width.  Siblings of the selected window are resized to
+   fullfil the size request.  If they become too small in the process,
+   they will be deleted.  */
 
+static void
+enlarge_window (window, delta, widthflag)
+     Lisp_Object window;
+     int delta, widthflag;
+{
+  Lisp_Object parent, next, prev;
+  struct window *p;
+  int *sizep, maximum;
+  int (*sizefun) P_ ((Lisp_Object))
+    = widthflag ? window_width : window_height;
+  void (*setsizefun) P_ ((Lisp_Object, int, int))
+    = (widthflag ? set_window_width : set_window_height);
+
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
   check_min_window_sizes ();
 
-  window = selected_window;
+  /* Give up if this window cannot be resized.  */
+  if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
+    error ("Window is not resizable");
+
+  /* Find the parent of the selected window.  */
   while (1)
     {
       p = XWINDOW (window);
       parent = p->parent;
+      
       if (NILP (parent))
        {
          if (widthflag)
            error ("No other window to side of this one");
          break;
        }
-      if (widthflag ? !NILP (XWINDOW (parent)->hchild)
+      
+      if (widthflag
+         ? !NILP (XWINDOW (parent)->hchild)
          : !NILP (XWINDOW (parent)->vchild))
        break;
+      
       window = parent;
     }
 
@@ -2578,8 +3140,12 @@ change_window_height (delta, widthflag)
     register int maxdelta;
 
     maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
-               : !NILP (p->next) ? (*sizefun) (p->next) - MINSIZE (p->next)
-               : !NILP (p->prev) ? (*sizefun) (p->prev) - MINSIZE (p->prev)
+               : !NILP (p->next) ? ((*sizefun) (p->next)
+                                    - window_min_size (XWINDOW (p->next),
+                                                       widthflag, 0, 0))
+               : !NILP (p->prev) ? ((*sizefun) (p->prev)
+                                    - window_min_size (XWINDOW (p->prev),
+                                                       widthflag, 0, 0))
                /* This is a frame with only one window, a minibuffer-only
                   or a minibufferless frame.  */
                : (delta = 0));
@@ -2591,7 +3157,7 @@ change_window_height (delta, widthflag)
       delta = maxdelta;
   }
 
-  if (*sizep + delta < MINSIZE (window))
+  if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
     {
       delete_window (window);
       return;
@@ -2603,15 +3169,18 @@ change_window_height (delta, widthflag)
   /* 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);
+    maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
+                                                   widthflag, 0, 0);
   for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
-    maximum += (*sizefun) (prev) - MINSIZE (prev);
+    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+                                                   widthflag, 0, 0);
 
   /* If we can get it all from them, do so.  */
-  if (delta < maximum)
+  if (delta <= maximum)
     {
       Lisp_Object first_unaffected;
       Lisp_Object first_affected;
+      int fixed_p;
 
       next = p->next;
       prev = p->prev;
@@ -2619,40 +3188,54 @@ change_window_height (delta, widthflag)
       /* 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)
+      while (delta != 0 && (!NILP (next) || !NILP (prev)))
        {
-         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);
+             int this_one = ((*sizefun) (next)
+                             - window_min_size (XWINDOW (next),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+                 
+                 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
+                 (*setsizefun) (window, *sizep + this_one, 0);
 
-             delta -= this_one;
+                 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;
+             int this_one = ((*sizefun) (prev)
+                             - window_min_size (XWINDOW (prev),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+                 
+                 first_affected = prev;
+                 
+                 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
+                 (*setsizefun) (window, *sizep + this_one, 0);
+
+                 delta -= this_one;
+               }
+             
              prev = XWINDOW (prev)->prev;
            }
        }
 
+      xassert (delta == 0);
+
       /* Now recalculate the edge positions of all the windows affected,
         based on the new sizes.  */
       first_unaffected = next;
@@ -2676,12 +3259,49 @@ change_window_height (delta, widthflag)
         all the siblings end up with less than one line and are deleted.  */
       if (opht <= *sizep + delta)
        delta1 = opht * opht * 2;
-      /* Otherwise, make delta1 just right so that if we add delta1
-        lines to this window and to the parent, and then shrink
-        the parent back to its original size, the new proportional
-        size of this window will increase by delta.  */
       else
-       delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
+       {
+         /* Otherwise, make delta1 just right so that if we add
+            delta1 lines to this window and to the parent, and then
+            shrink the parent back to its original size, the new
+            proportional size of this window will increase by delta.
+
+            The function size_window will compute the new height h'
+            of the window from delta1 as:
+            
+            e = delta1/n
+            x = delta1 - delta1/n * n for the 1st resizable child
+            h' = h + e + x
+
+            where n is the number of children that can be resized.
+            We can ignore x by choosing a delta1 that is a multiple of
+            n.  We want the height of this window to come out as
+            
+            h' = h + delta
+
+            So, delta1 must be
+            
+            h + e = h + delta
+            delta1/n = delta
+            delta1 = n * delta.
+
+            The number of children n rquals the number of resizable
+            children of this window + 1 because we know window itself
+            is resizable (otherwise we would have signalled an error.  */
+
+         struct window *w = XWINDOW (window);
+         Lisp_Object s;
+         int n = 1;
+
+         for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
+           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+             ++n;
+         for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
+           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+             ++n;
+
+         delta1 = n * delta;
+       }
 
       /* Add delta1 lines or columns to this window, and to the parent,
         keeping things consistent while not affecting siblings.  */
@@ -2698,12 +3318,271 @@ change_window_height (delta, widthflag)
 
   XSETFASTINT (p->last_modified, 0);
   XSETFASTINT (p->last_overlay_modified, 0);
+
+  /* Adjust glyph matrices. */
+  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
 }
-#undef MINSIZE
+
 #undef CURBEG
 #undef CURSIZE
 
+
 \f
+/***********************************************************************
+                       Resizing Mini-Windows
+ ***********************************************************************/
+
+static void shrink_window_lowest_first P_ ((struct window *, int));
+
+enum save_restore_action
+{
+    CHECK_ORIG_SIZES,
+    SAVE_ORIG_SIZES,
+    RESTORE_ORIG_SIZES
+};
+
+static int save_restore_orig_size P_ ((struct window *, 
+                                       enum save_restore_action));
+
+/* Shrink windows rooted in window W to HEIGHT.  Take the space needed
+   from lowest windows first.  */
+
+static void
+shrink_window_lowest_first (w, height)
+     struct window *w;
+     int height;
+{
+  struct window *c;
+  Lisp_Object child;
+  int old_height;
+
+  xassert (!MINI_WINDOW_P (w));
+
+  /* Set redisplay hints.  */
+  XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
+  windows_or_buffers_changed++;
+  FRAME_WINDOW_SIZES_CHANGED (XFRAME (WINDOW_FRAME (w))) = 1;
+
+  old_height = XFASTINT (w->height);
+  XSETFASTINT (w->height, height);
+
+  if (!NILP (w->hchild))
+    {
+      for (child = w->hchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top = w->top;
+         shrink_window_lowest_first (c, height);
+       }
+    }
+  else if (!NILP (w->vchild))
+    {
+      Lisp_Object last_child;
+      int delta = old_height - height;
+      int last_top;
+      
+      /* Find the last child.  We are taking space from lowest windows
+        first, so we iterate over children from the last child
+        backwards.  */
+      for (child = w->vchild; !NILP (child); child = XWINDOW (child)->next)
+       last_child = child;
+
+      /* Assign new heights.  We leave only MIN_SAFE_WINDOW_HEIGHT.  */
+      for (child = last_child; delta && !NILP (child); child = c->prev)
+       {
+         int this_one;
+         
+         c = XWINDOW (child);
+         this_one = XFASTINT (c->height) - MIN_SAFE_WINDOW_HEIGHT;
+
+         if (this_one > delta)
+           this_one = delta;
+
+         shrink_window_lowest_first (c, XFASTINT (c->height) - this_one);
+         delta -= this_one;
+       }
+
+      /* Compute new positions.  */
+      last_top = w->top;
+      for (child = w->vchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top = make_number (last_top);
+         shrink_window_lowest_first (c, XFASTINT (c->height));
+         last_top += XFASTINT (c->height);
+       }
+    }
+}
+
+
+/* Save, restore, or check positions and sizes in the window tree
+   rooted at W.  ACTION says what to do.
+
+   If ACTION is CHECK_ORIG_SIZES, check if orig_top and orig_height
+   members are valid for all windows in the window tree.  Value is
+   non-zero if they are valid.
+   
+   If ACTION is SAVE_ORIG_SIZES, save members top and height in
+   orig_top and orig_height for all windows in the tree.
+
+   If ACTION is RESTORE_ORIG_SIZES, restore top and height from
+   values stored in orig_top and orig_height for all windows.  */
+
+static int
+save_restore_orig_size (w, action)
+     struct window *w;
+     enum save_restore_action action;
+{
+  int success_p = 1;
+
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       {
+         if (!save_restore_orig_size (XWINDOW (w->hchild), action))
+           success_p = 0;
+       }
+      else if (!NILP (w->vchild))
+       {
+         if (!save_restore_orig_size (XWINDOW (w->vchild), action))
+           success_p = 0;
+       }
+      
+      switch (action)
+       {
+       case CHECK_ORIG_SIZES:
+         if (!INTEGERP (w->orig_top) || !INTEGERP (w->orig_height))
+           return 0;
+         break;
+
+       case SAVE_ORIG_SIZES:
+         w->orig_top = w->top;
+         w->orig_height = w->height;
+          XSETFASTINT (w->last_modified, 0);
+          XSETFASTINT (w->last_overlay_modified, 0);
+         break;
+
+       case RESTORE_ORIG_SIZES:
+         xassert (INTEGERP (w->orig_top) && INTEGERP (w->orig_height));
+         w->top = w->orig_top;
+         w->height = w->orig_height;
+         w->orig_height = w->orig_top = Qnil;
+          XSETFASTINT (w->last_modified, 0);
+          XSETFASTINT (w->last_overlay_modified, 0);
+         break;
+
+       default:
+         abort ();
+       }
+
+      w = NILP (w->next) ? NULL : XWINDOW (w->next);
+    }
+
+  return success_p;
+}
+
+
+/* Grow mini-window W by DELTA lines, DELTA >= 0, or as much as we can
+   without deleting other windows.  */
+
+void
+grow_mini_window (w, delta)
+     struct window *w;
+     int delta;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct window *root;
+  
+  xassert (MINI_WINDOW_P (w));
+  xassert (delta >= 0);
+          
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
+  check_min_window_sizes ();
+
+  /* Compute how much we can enlarge the mini-window without deleting
+     other windows.  */
+  root = XWINDOW (FRAME_ROOT_WINDOW (f));
+  if (delta)
+    {
+      int min_height = window_min_size (root, 0, 0, 0);
+      if (XFASTINT (root->height) - delta < min_height)
+       delta = XFASTINT (root->height) - min_height;
+    }
+    
+  if (delta)
+    {
+      /* Save original window sizes and positions, if not already done.  */
+      if (!save_restore_orig_size (root, CHECK_ORIG_SIZES))
+       save_restore_orig_size (root, SAVE_ORIG_SIZES);
+
+      /* Shrink other windows.  */
+      shrink_window_lowest_first (root, XFASTINT (root->height) - delta);
+
+      /* Grow the mini-window.  */
+      w->top = make_number (XFASTINT (root->top) + XFASTINT (root)->height);
+      w->height = make_number (XFASTINT (w->height) + delta);
+      XSETFASTINT (w->last_modified, 0);
+      XSETFASTINT (w->last_overlay_modified, 0);
+      
+      adjust_glyphs (f);
+    }
+}
+
+
+/* Shrink mini-window W.  If there is recorded info about window sizes
+   before a call to grow_mini_window, restore recorded window sizes.
+   Otherwise, if the mini-window is higher than 1 line, resize it to 1
+   line.  */
+
+void
+shrink_mini_window (w)
+     struct window *w;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct window *root = XWINDOW (FRAME_ROOT_WINDOW (f));
+
+  if (save_restore_orig_size (root, CHECK_ORIG_SIZES))
+    {
+      save_restore_orig_size (root, RESTORE_ORIG_SIZES);
+      adjust_glyphs (f);
+      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+      windows_or_buffers_changed = 1;
+    }
+  else if (XFASTINT (w->height) > 1)
+    {
+      Lisp_Object window;
+      XSETWINDOW (window, w);
+      enlarge_window (window, 1 - XFASTINT (w->height), 0);
+    }
+}
+
+
+\f
+/* Mark window cursors off for all windows in the window tree rooted
+   at W by setting their phys_cursor_on_p flag to zero.  Called from
+   xterm.c, e.g. when a frame is cleared and thereby all cursors on
+   the frame are cleared.  */
+
+void
+mark_window_cursors_off (w)
+     struct window *w;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       mark_window_cursors_off (XWINDOW (w->hchild));
+      else if (!NILP (w->vchild))
+       mark_window_cursors_off (XWINDOW (w->vchild));
+      else
+       w->phys_cursor_on_p = 0;
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
+
+
 /* Return number of lines of text (not counting mode line) in W.  */
 
 int
@@ -2727,28 +3606,41 @@ window_internal_height (w)
 /* Return the number of columns in W.
    Don't count columns occupied by scroll bars or the vertical bar
    separating W from the sibling to its right.  */
+
 int
 window_internal_width (w)
      struct window *w;
 {
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
   int width = XINT (w->width);
 
-  /* 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.  */
-  if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
-    return width - 1;
+    /* Scroll bars occupy a few columns.  */
+    width -= FRAME_SCROLL_BAR_COLS (f);
+  else if (!WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+    /* The column of `|' characters separating side-by-side windows
+       occupies one column only.  */
+    width -= 1;
+
+  /* On window-systems, areas to the left and right of the window
+     are used to display bitmaps there.  */
+  if (FRAME_WINDOW_P (f))
+    width -= FRAME_FLAGS_AREA_COLS (f);
 
   return width;
 }
 
+\f
+/************************************************************************
+                          Window Scrolling
+ ***********************************************************************/
 
-/* Scroll contents of window WINDOW up N lines.
-   If WHOLE is nonzero, it means scroll N screenfuls instead.  */
+/* Scroll contents of window WINDOW up.  If WHOLE is non-zero, scroll
+   one screen-full, which is defined as the height of the window minus
+   next_screen_context_lines.  If WHOLE is zero, scroll up N lines
+   instead.  Negative values of N mean scroll down.  NOERROR non-zero
+   means don't signal an error if we try to move over BEGV or ZV,
+   respectively.  */
 
 static void
 window_scroll (window, n, whole, noerror)
@@ -2756,14 +3648,170 @@ window_scroll (window, n, whole, noerror)
      int n;
      int whole;
      int noerror;
+{
+  /* If we must, use the pixel-based version which is much slower than
+     the line-based one but can handle varying line heights.  */
+  if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
+    window_scroll_pixel_based (window, n, whole, noerror);
+  else
+    window_scroll_line_based (window, n, whole, noerror);
+}
+
+
+/* Implementation of window_scroll that works based on pixel line
+   heights.  See the comment of window_scroll for parameter
+   descriptions.  */
+
+static void
+window_scroll_pixel_based (window, n, whole, noerror)
+     Lisp_Object window;
+     int n;
+     int whole;
+     int noerror;
+{
+  struct it it;
+  struct window *w = XWINDOW (window);
+  struct text_pos start;
+  Lisp_Object tem;
+  int this_scroll_margin;
+  int preserve_y;
+
+  SET_TEXT_POS_FROM_MARKER (start, w->start);
+  
+  /* If PT is not visible in WINDOW, move back one half of
+     the screen.  */
+  XSETFASTINT (tem, PT);
+  tem = Fpos_visible_in_window_p (tem, window);
+  if (NILP (tem))
+    {
+      /* Move backward half the height of the window.  Performance note:
+        vmotion used here is about 10% faster, but would give wrong
+        results for variable height lines.  */
+      init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+      it.current_y = it.last_visible_y;
+      move_it_vertically (&it, -it.last_visible_y / 2);
+      
+      /* The function move_iterator_vertically may move over more than
+        the specified y-distance.  If it->w is small, e.g. a
+        mini-buffer window, we may end up in front of the window's
+        display area.  This is the case when Start displaying at the
+        start of the line containing PT in this case.  */
+      if (it.current_y <= 0)
+       {
+         init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+         move_it_vertically (&it, 0);
+         it.current_y = 0;
+       }
+
+      start = it.current.pos;
+    }
+
+  /* If scroll_preserve_screen_position is non-zero, we try to set
+     point in the same window line as it is now, so get that line.  */
+  if (!NILP (Vscroll_preserve_screen_position))
+    {
+      start_display (&it, w, start);
+      move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+      preserve_y = it.current_y;
+    }
+  else
+    preserve_y = -1;
+
+  /* Move iterator it from start the specified distance forward or
+     backward.  The result is the new window start.  */
+  start_display (&it, w, start);
+  if (whole)
+    {
+      int screen_full = (it.last_visible_y
+                        - next_screen_context_lines * CANON_Y_UNIT (it.f));
+      int direction = n < 0 ? -1 : 1;
+      move_it_vertically (&it, direction * screen_full);
+    }
+  else
+    move_it_by_lines (&it, n, 1);
+
+  /* End if we end up at ZV or BEGV.  */
+  if ((n > 0 && IT_CHARPOS (it) == ZV)
+      || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
+    {
+      if (noerror)
+       return;
+      else if (IT_CHARPOS (it) == ZV)
+       Fsignal (Qend_of_buffer, Qnil);
+      else
+       Fsignal (Qbeginning_of_buffer, Qnil);
+    }
+
+  /* Set the window start, and set up the window for redisplay.  */
+  set_marker_restricted (w->start, make_number (IT_CHARPOS (it)), w->buffer);
+  w->start_at_line_beg = Fbolp ();
+  w->update_mode_line = Qt;
+  XSETFASTINT (w->last_modified, 0);
+  XSETFASTINT (w->last_overlay_modified, 0);
+  /* Set force_start so that redisplay_window will run the
+     window-scroll-functions.  */
+  w->force_start = Qt;
+  
+  it.current_y = it.vpos = 0;
+  
+  /* Preserve the screen position if we must.  */
+  if (preserve_y >= 0)
+    {
+      move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+      SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+    }
+  else
+    {
+      /* Move PT out of scroll margins.  */
+      this_scroll_margin = max (0, scroll_margin);
+      this_scroll_margin = min (this_scroll_margin, XFASTINT (w->height) / 4);
+      this_scroll_margin *= CANON_Y_UNIT (it.f);
+
+      if (n > 0)
+       {
+         /* We moved the window start towards ZV, so PT may be now
+            in the scroll margin at the top.  */
+         move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+         while (it.current_y < this_scroll_margin)
+           move_it_by_lines (&it, 1, 1);
+         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+       }
+      else if (n < 0)
+       {
+         /* We moved the window start towards BEGV, so PT may be now
+            in the scroll margin at the bottom.  */
+         move_it_to (&it, PT, -1,
+                     it.last_visible_y - this_scroll_margin - 1, -1,
+                     MOVE_TO_POS | MOVE_TO_Y);
+      
+         /* Don't put point on a partially visible line at the end.  */
+         if (it.current_y + it.max_ascent + it.max_descent
+             > it.last_visible_y)
+           move_it_by_lines (&it, -1, 0);
+      
+         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+       }
+    }
+}
+
+
+/* Implementation of window_scroll that works based on screen lines.
+   See the comment of window_scroll for parameter descriptions.  */
+
+static void
+window_scroll_line_based (window, n, whole, noerror)
+     Lisp_Object window;
+     int n;
+     int whole;
+     int noerror;
 {
   register struct window *w = XWINDOW (window);
-  register int opoint = PT;
-  register int pos;
+  register int opoint = PT, opoint_byte = PT_BYTE;
+  register int pos, pos_byte;
   register int ht = window_internal_height (w);
   register Lisp_Object tem;
   int lose;
-  Lisp_Object bolp, nmoved;
+  Lisp_Object bolp;
   int startpos;
   struct position posit;
   int original_vpos;
@@ -2789,8 +3837,9 @@ window_scroll (window, n, whole, noerror)
   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)
     {
@@ -2811,7 +3860,7 @@ window_scroll (window, n, whole, noerror)
       if (XINT (w->height) < 4 * scroll_margin)
        this_scroll_margin = XINT (w->height) / 4;
 
-      set_marker_restricted (w->start, make_number (pos), w->buffer);
+      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);
@@ -2820,9 +3869,9 @@ window_scroll (window, n, whole, noerror)
         the window-scroll-functions.  */
       w->force_start = Qt;
 
-      if (whole && scroll_preserve_screen_position)
+      if (whole && !NILP (Vscroll_preserve_screen_position))
        {
-         SET_PT (pos);
+         SET_PT_BOTH (pos, pos_byte);
          Fvertical_motion (make_number (original_vpos), window);
        }
       /* If we scrolled forward, put point enough lines down
@@ -2833,7 +3882,7 @@ window_scroll (window, n, whole, noerror)
 
          if (this_scroll_margin > 0)
            {
-             SET_PT (pos);
+             SET_PT_BOTH (pos, pos_byte);
              Fvertical_motion (make_number (this_scroll_margin), window);
              top_margin = PT;
            }
@@ -2841,14 +3890,14 @@ window_scroll (window, n, whole, noerror)
            top_margin = pos;
 
          if (top_margin <= opoint)
-           SET_PT (opoint);
-         else if (scroll_preserve_screen_position)
+           SET_PT_BOTH (opoint, opoint_byte);
+         else if (!NILP (Vscroll_preserve_screen_position))
            {
-             SET_PT (pos);
+             SET_PT_BOTH (pos, pos_byte);
              Fvertical_motion (make_number (original_vpos), window);
            }
          else
-           SET_PT (pos);
+           SET_PT (top_margin);
        }
       else if (n < 0)
        {
@@ -2856,7 +3905,7 @@ window_scroll (window, n, whole, noerror)
 
          /* If we scrolled backward, put point near the end of the window
             but not within the scroll margin.  */
-         SET_PT (pos);
+         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;
@@ -2864,12 +3913,12 @@ window_scroll (window, n, whole, noerror)
            bottom_margin = PT + 1;
 
          if (bottom_margin > opoint)
-           SET_PT (opoint);
+           SET_PT_BOTH (opoint, opoint_byte);
          else
            {
-             if (scroll_preserve_screen_position)
+             if (!NILP (Vscroll_preserve_screen_position))
                {
-                 SET_PT (pos);
+                 SET_PT_BOTH (pos, pos_byte);
                  Fvertical_motion (make_number (original_vpos), window);
                }
              else
@@ -2885,23 +3934,33 @@ window_scroll (window, n, whole, noerror)
        Fsignal (Qend_of_buffer, Qnil);
     }
 }
-\f
-/* This is the guts of Fscroll_up and Fscroll_down.  */
+
+
+/* Scroll selected_window up or down.  If N is nil, scroll a
+   screen-full which is defined as the height of the window minus
+   next_screen_context_lines.  If N is the symbol `-', scroll.
+   DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
+   up.  This is the guts of Fscroll_up and Fscroll_down.  */
 
 static void
 scroll_command (n, direction)
-     register Lisp_Object n;
+     Lisp_Object n;
      int direction;
 {
   register int defalt;
   int count = specpdl_ptr - specpdl;
 
-  /* If selected window's buffer isn't current, make it current for the moment.
-     But don't screw up if window_scroll gets an error.  */
+  xassert (abs (direction) == 1);
+
+  /* If selected window's buffer isn't current, make it current for
+     the moment.  But don't screw up if window_scroll gets an error.  */
   if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
     {
       record_unwind_protect (save_excursion_restore, save_excursion_save ());
       Fset_buffer (XWINDOW (selected_window)->buffer);
+
+      /* Make redisplay consider other windows than just selected_window.  */
+      ++windows_or_buffers_changed;
     }
 
   defalt = (window_internal_height (XWINDOW (selected_window))
@@ -2925,7 +3984,8 @@ DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
   "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2934,10 +3994,11 @@ When calling from a program, supply a number as argument or nil.")
 }
 
 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
-  "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
+  "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll upward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll upward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2963,7 +4024,7 @@ showing that buffer is used.")
     {
       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
       if (NILP (window))
-       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
+       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
     }
   else
     {
@@ -2990,9 +4051,11 @@ showing that buffer is used.")
 
 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
   "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
+A near full screen is `next-screen-context-lines' less than a full screen.\n\
 The next window is the one below the current one; or the one at the top\n\
 if the current one is at the bottom.  Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.\n\
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.\n\
 \n\
 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
 specifies the window to scroll.\n\
@@ -3014,6 +4077,7 @@ showing that buffer, popping the buffer up if necessary.")
 
   /* Don't screw up if window_scroll gets an error.  */
   record_unwind_protect (save_excursion_restore, save_excursion_save ());
+  ++windows_or_buffers_changed;
 
   Fset_buffer (w->buffer);
   SET_PT (marker_position (w->pointm));
@@ -3030,7 +4094,7 @@ showing that buffer, popping the buffer up if necessary.")
       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;
@@ -3083,11 +4147,14 @@ redraws with point in the center of the current window.")
   register struct window *w = XWINDOW (selected_window);
   register int ht = window_internal_height (w);
   struct position pos;
+  struct buffer *buf = XBUFFER (w->buffer);
+  struct buffer *obuf = current_buffer;
 
   if (NILP (arg))
     {
       extern int frame_garbaged;
 
+      Fredraw_frame (w->frame);
       SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
       XSETFASTINT (arg, ht / 2);
     }
@@ -3104,13 +4171,15 @@ redraws with point in the center of the current window.")
   if (XINT (arg) < 0)
     XSETINT (arg, XINT (arg) + ht);
 
+  set_buffer_internal (buf);
   pos = *vmotion (PT, - XINT (arg), w);
 
-  Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
-  w->start_at_line_beg = ((pos.bufpos == BEGV
-                          || FETCH_BYTE (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;
 }
@@ -3119,8 +4188,8 @@ DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
   1, 1, "P",
   "Position point relative to window.\n\
 With no argument, position point at center of window.\n\
-An argument specifies frame line; zero means top of window,\n\
-negative means relative to bottom of window.")
+An argument specifies vertical position within the window;\n\
+zero means top of window, negative means relative to bottom of window.")
   (arg)
      register Lisp_Object arg;
 {
@@ -3143,21 +4212,28 @@ negative means relative to bottom of window.")
   if (start < BEGV || start > ZV)
     {
       Fvertical_motion (make_number (- (height / 2)), window);
-      Fset_marker (w->start, make_number (PT), w->buffer);
+      set_marker_both (w->start, w->buffer, PT, PT_BYTE);
       w->start_at_line_beg = Fbolp ();
       w->force_start = Qt;
     }
   else
-    SET_PT (start);
+    Fgoto_char (w->start);
 
   return Fvertical_motion (arg, window);
 }
+
+
 \f
+/***********************************************************************
+                        Window Configuration
+ ***********************************************************************/
+
 struct save_window_data
   {
     EMACS_INT size_from_Lisp_Vector_struct;
     struct Lisp_Vector *next_from_Lisp_Vector_struct;
     Lisp_Object frame_width, frame_height, frame_menu_bar_lines;
+    Lisp_Object frame_tool_bar_lines;
     Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object current_buffer;
@@ -3167,11 +4243,12 @@ struct save_window_data
     /* Record the values of window-min-width and window-min-height
        so that window sizes remain consistent with them.  */
     Lisp_Object min_width, min_height;
-    /* A vector, interpreted as a struct saved_window */
+    /* A vector, each of whose elements is a struct saved_window
+       for one window.  */
     Lisp_Object saved_windows;
   };
 
-/* This is saved as a Lisp_Vector */
+/* This is saved as a Lisp_Vector  */
 struct saved_window
   {
     /* these first two must agree with struct Lisp_Vector in lisp.h */
@@ -3191,7 +4268,7 @@ struct saved_window
   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
 
 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
-  "T if OBJECT is a window-configuration object.")
+  "Return t if OBJECT is a window-configuration object.")
   (object)
      Lisp_Object object;
 {
@@ -3200,13 +4277,31 @@ DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_
   return Qnil;
 }
 
+DEFUN ("window-configuration-frame", Fwindow_configuration_frame, Swindow_configuration_frame, 1, 1, 0,
+  "Return the frame that CONFIG, a window-configuration object, is about.")
+  (config)
+     Lisp_Object config;
+{
+  register struct save_window_data *data;
+  struct Lisp_Vector *saved_windows;
+
+  if (! WINDOW_CONFIGURATIONP (config))
+    wrong_type_argument (Qwindow_configuration_p, config);
+
+  data = (struct save_window_data *) XVECTOR (config);
+  saved_windows = XVECTOR (data->saved_windows);
+  return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
+}
 
 DEFUN ("set-window-configuration", Fset_window_configuration,
   Sset_window_configuration, 1, 1, 0,
   "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
 CONFIGURATION must be a value previously returned\n\
-by `current-window-configuration' (which see).")
-     (configuration)
+by `current-window-configuration' (which see).\n\
+If CONFIGURATION was made from a frame that is now deleted,\n\
+only frame-independent values can be restored.  In this case,\n\
+the return value is nil.  Otherwise the value is t.")
+  (configuration)
      Lisp_Object configuration;
 {
   register struct save_window_data *data;
@@ -3217,10 +4312,7 @@ by `current-window-configuration' (which see).")
   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);
@@ -3232,6 +4324,7 @@ by `current-window-configuration' (which see).")
     {
       if (XBUFFER (new_current_buffer) == current_buffer)
        old_point = PT;
+
     }
 
   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
@@ -3243,7 +4336,10 @@ by `current-window-configuration' (which see).")
     {
       register struct window *w;
       register struct saved_window *p;
-      int k;
+      struct window *root_window;
+      struct window **leaf_windows;
+      int n_leaf_windows;
+      int k, i;
 
       /* If the frame has been resized since this window configuration was
         made, we change the frame to the size specified in the
@@ -3252,6 +4348,7 @@ by `current-window-configuration' (which see).")
       int previous_frame_height = FRAME_HEIGHT (f);
       int previous_frame_width =  FRAME_WIDTH  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
+      int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
 
       /* The mouse highlighting code could get screwed up
         if it runs during this.  */
@@ -3259,16 +4356,41 @@ by `current-window-configuration' (which see).")
 
       if (XFASTINT (data->frame_height) != previous_frame_height
          || XFASTINT (data->frame_width) != previous_frame_width)
-       change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
+       change_frame_size (f, XFASTINT (data->frame_height),
+                          XFASTINT (data->frame_width), 0, 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (XFASTINT (data->frame_menu_bar_lines)
          != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
+#ifdef HAVE_WINDOW_SYSTEM
+      if (XFASTINT (data->frame_tool_bar_lines)
+         != previous_frame_tool_bar_lines)
+       x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
 #endif
+#endif
+
+      if (! NILP (XWINDOW (selected_window)->buffer))
+       {
+         w = XWINDOW (selected_window);
+         set_marker_both (w->pointm,
+                          w->buffer,
+                          BUF_PT (XBUFFER (w->buffer)),
+                          BUF_PT_BYTE (XBUFFER (w->buffer)));
+       }
 
       windows_or_buffers_changed++;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
+      /* Problem: Freeing all matrices and later allocating them again
+        is a serious redisplay flickering problem.  What we would 
+        really like to do is to free only those matrices not reused
+        below.   */
+      root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
+      leaf_windows
+       = (struct window **) alloca (count_windows (root_window)
+                                    * sizeof (struct window *));
+      n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
+
       /* Temporarily avoid any problems with windows that are smaller
         than they are supposed to be.  */
       window_min_height = 1;
@@ -3342,14 +4464,10 @@ by `current-window-configuration' (which see).")
                {
                  w->buffer = p->buffer;
                  w->start_at_line_beg = p->start_at_line_beg;
-                 set_marker_restricted (w->start,
-                                        Fmarker_position (p->start),
-                                        w->buffer);
-                 set_marker_restricted (w->pointm,
-                                        Fmarker_position (p->pointm),
-                                        w->buffer);
+                 set_marker_restricted (w->start, p->start, w->buffer);
+                 set_marker_restricted (w->pointm, p->pointm, w->buffer);
                  Fset_marker (XBUFFER (w->buffer)->mark,
-                              Fmarker_position (p->mark), w->buffer);
+                              p->mark, w->buffer);
 
                  /* As documented in Fcurrent_window_configuration, don't
                     save the location of point in the buffer which was current
@@ -3377,10 +4495,9 @@ by `current-window-configuration' (which see).")
                    set_marker_restricted (w->start, make_number (0),
                                           w->buffer);
                  if (XMARKER (w->pointm)->buffer == 0)
-                   set_marker_restricted (w->pointm,
-                                          (make_number
-                                           (BUF_PT (XBUFFER (w->buffer)))),
-                                          w->buffer);
+                   set_marker_restricted_both (w->pointm, w->buffer,
+                                               BUF_PT (XBUFFER (w->buffer)),
+                                               BUF_PT_BYTE (XBUFFER (w->buffer)));
                  w->start_at_line_beg = Qt;
                }
            }
@@ -3407,26 +4524,45 @@ by `current-window-configuration' (which see).")
       if (previous_frame_height != FRAME_HEIGHT (f)
          || previous_frame_width != FRAME_WIDTH (f))
        change_frame_size (f, previous_frame_height, previous_frame_width,
-                          0, 0);
+                          0, 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
-       x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
+                             make_number (0));
+#ifdef HAVE_WINDOW_SYSTEM
+      if (previous_frame_tool_bar_lines != FRAME_TOOL_BAR_LINES (f))
+       x_set_tool_bar_lines (f, make_number (previous_frame_tool_bar_lines),
+                             make_number (0));
+#endif
 #endif
 
-      UNBLOCK_INPUT;
-    }
+      /* Now, free glyph matrices in windows that were not reused.  */
+      for (i = 0; i < n_leaf_windows; ++i)
+       if (NILP (leaf_windows[i]->buffer))
+         {
+           /* Assert it's not reused as a combination.  */
+           xassert (NILP (leaf_windows[i]->hchild) 
+                    && NILP (leaf_windows[i]->vchild));
+           free_window_matrices (leaf_windows[i]);
+           SET_FRAME_GARBAGED (f);
+         }
+      
+      adjust_glyphs (f);
 
-  /* Restore the minimum heights recorded in the configuration.  */
-  window_min_height = XINT (data->min_height);
-  window_min_width = XINT (data->min_width);
+      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);
+      /* 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))
     {
@@ -3439,13 +4575,13 @@ by `current-window-configuration' (which see).")
        SET_PT (old_point);
     }
 
-  Vminibuf_scroll_window = data->minibuf_scroll_window;
+  /* Restore the minimum heights recorded in the configuration.  */
+  window_min_height = XINT (data->min_height);
+  window_min_width = XINT (data->min_width);
 
-  if (! NILP (Vwindow_configuration_change_hook)
-      && ! NILP (Vrun_hooks))
-    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+  Vminibuf_scroll_window = data->minibuf_scroll_window;
 
-  return (Qnil);
+  return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
 
 /* Mark all windows now on frame as deleted
@@ -3490,6 +4626,56 @@ count_windows (window)
   return count;
 }
 
+
+/* Fill vector FLAT with leaf windows under W, starting at index I.  
+   Value is last index + 1.  */
+
+static int
+get_leaf_windows (w, flat, i)
+     struct window *w;
+     struct window **flat;
+     int i;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
+      else if (!NILP (w->vchild))
+       i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
+      else 
+       flat[i++] = w;
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+
+  return i;
+}
+
+
+/* Return a pointer to the glyph W's physical cursor is on.  Value is
+   null if W's current matrix is invalid, so that no meaningfull glyph
+   can be returned.  */
+
+struct glyph *
+get_phys_cursor_glyph (w)
+     struct window *w;
+{
+  struct glyph_row *row;
+  struct glyph *glyph;
+
+  if (w->phys_cursor.vpos >= 0
+      && w->phys_cursor.vpos < w->current_matrix->nrows
+      && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
+         row->enabled_p)
+      && row->used[TEXT_AREA] > w->phys_cursor.hpos)
+    glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
+  else
+    glyph = NULL;
+
+  return glyph;
+}
+
+
 static int
 save_window_save (window, vector, i)
      Lisp_Object window;
@@ -3522,9 +4708,9 @@ save_window_save (window, vector, i)
          if (EQ (window, selected_window))
            {
              p->pointm = Fmake_marker ();
-             Fset_marker (p->pointm,
-                          make_number (BUF_PT (XBUFFER (w->buffer))),
-                          w->buffer);
+             set_marker_both (p->pointm, w->buffer,
+                              BUF_PT (XBUFFER (w->buffer)),
+                              BUF_PT_BYTE (XBUFFER (w->buffer)));
            }
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
@@ -3583,12 +4769,9 @@ redirection (see `redirect-frame-focus').")
   FRAME_PTR f;
 
   if (NILP (frame))
-    f = selected_frame;
-  else
-    {
-      CHECK_LIVE_FRAME (frame, 0);
-      f = XFRAME (frame);
-    }
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 0);
+  f = XFRAME (frame);
 
   n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
   vec = allocate_vectorlike (VECSIZE (struct save_window_data));
@@ -3600,7 +4783,8 @@ redirection (see `redirect-frame-focus').")
   XSETFASTINT (data->frame_width, FRAME_WIDTH (f));
   XSETFASTINT (data->frame_height, FRAME_HEIGHT (f));
   XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
-  XSETFRAME (data->selected_frame, selected_frame);
+  XSETFASTINT (data->frame_tool_bar_lines, FRAME_TOOL_BAR_LINES (f));
+  data->selected_frame = selected_frame;
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSETBUFFER (data->current_buffer, current_buffer);
   data->minibuf_scroll_window = Vminibuf_scroll_window;
@@ -3638,20 +4822,349 @@ Does not restore the value of point in current buffer.")
   val = Fprogn (args);
   return unbind_to (count, val);
 }
+
+\f
+/***********************************************************************
+                           Marginal Areas
+ ***********************************************************************/
+
+DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
+       2, 3, "",
+  "Set width of marginal areas of window WINDOW.\n\
+If window is nil or omitted, set margins of the currently selected window.\n\
+First parameter LEFT-WIDTH specifies the number of character\n\
+cells to reserve for the left marginal area.  Second parameter\n\
+RIGHT-WIDTH does the same for the right marginal area.\n\
+A nil width parameter means no margin.")
+  (window, left, right)
+     Lisp_Object window, left, right;
+{
+  struct window *w = decode_window (window);
+
+  if (!NILP (left))
+    CHECK_NUMBER_OR_FLOAT (left, 1);
+  if (!NILP (right))
+    CHECK_NUMBER_OR_FLOAT (right, 2);
+
+  /* Check widths < 0 and translate a zero width to nil.
+     Margins that are too wide have to be checked elsewhere.  */
+  if ((INTEGERP (left) && XINT (left) < 0)
+      || (FLOATP (left) && XFLOAT_DATA (left) <= 0))
+     XSETFASTINT (left, 0);
+  if (INTEGERP (left) && XFASTINT (left) == 0)
+    left = Qnil;
+  
+  if ((INTEGERP (right) && XINT (right) < 0)
+      || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
+    XSETFASTINT (right, 0);
+  if (INTEGERP (right) && XFASTINT (right) == 0)
+    right = Qnil;
+
+  w->left_margin_width = left;
+  w->right_margin_width = right;
+
+  ++windows_or_buffers_changed;
+  adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+  return Qnil;
+}
+
+
+DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
+       0, 1, 0,
+  "Get width of marginal areas of window WINDOW.\n\
+If WINDOW is omitted or nil, use the currently selected window.\n\
+Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).\n\
+If a marginal area does not exist, its width will be returned\n\
+as nil.")
+  (window)
+     Lisp_Object window;
+{
+  struct window *w = decode_window (window);
+  return Fcons (w->left_margin_width, w->right_margin_width);
+}
+
+
+\f
+/***********************************************************************
+                          Smooth scrolling
+ ***********************************************************************/
+
+DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
+  "Return the amount by which WINDOW is scrolled vertically.\n\
+Use the selected window if WINDOW is nil or omitted.\n\
+Value is a multiple of the canonical character height of WINDOW.")
+  (window)
+     Lisp_Object window;
+{
+  Lisp_Object result;
+  struct frame *f;
+  struct window *w;
+  
+  if (NILP (window))
+    window = selected_window;
+  else
+    CHECK_WINDOW (window, 0);
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
+  
+  if (FRAME_WINDOW_P (f))
+    result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
+  else
+    result = make_number (0);
+  return result;
+}
+
+
+DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
+       2, 2, 0,
+  "Set amount by which WINDOW should be scrolled vertically to VSCROLL.\n\
+WINDOW nil or omitted means use the selected window.  VSCROLL is a\n\
+non-negative multiple of the canonical character height of WINDOW.")
+  (window, vscroll)
+     Lisp_Object window, vscroll;
+{
+  struct window *w;
+  struct frame *f;
+  
+  if (NILP (window))
+    window = selected_window;
+  else
+    CHECK_WINDOW (window, 0);
+  CHECK_NUMBER_OR_FLOAT (vscroll, 1);
+  
+  w = XWINDOW (window);
+  f = XFRAME (w->frame);
+
+  if (FRAME_WINDOW_P (f))
+    {
+      int old_dy = w->vscroll;
+      
+      w->vscroll = - CANON_Y_UNIT (f) * XFLOATINT (vscroll);
+      w->vscroll = min (w->vscroll, 0);
+
+      /* Adjust glyph matrix of the frame if the virtual display
+        area becomes larger than before.  */
+      if (w->vscroll < 0 && w->vscroll < old_dy)
+       adjust_glyphs (f);
+      
+      /* Prevent redisplay shortcuts.  */
+      XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+    }
+  
+  return Fwindow_vscroll (window);
+}
+       
 \f
+/* Call FN for all leaf windows on frame F.  FN is called with the
+   first argument being a pointer to the leaf window, and with
+   additional arguments A1..A4.  */
+
+void
+foreach_window (f, fn, a1, a2, a3, a4)
+     struct frame *f;
+     void (* fn) ();
+     int a1, a2, a3, a4;
+{
+  foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, a1, a2, a3, a4);
+}
+
+
+/* Helper function for foreach_window.  Call FN for all leaf windows
+   reachable from W.  FN is called with the first argument being a
+   pointer to the leaf window, and with additional arguments A1..A4.  */
+
+static void
+foreach_window_1 (w, fn, a1, a2, a3, a4)
+     struct window *w;
+     void (* fn) ();
+     int a1, a2, a3, a4;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       foreach_window_1 (XWINDOW (w->hchild), fn, a1, a2, a3, a4);
+      else if (!NILP (w->vchild))
+       foreach_window_1 (XWINDOW (w->vchild), fn, a1, a2, a3, a4);
+      else
+       fn (w, a1, a2, a3, a4);
+      
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
+
+
+/* Freeze or unfreeze the window start of W if unless it is a
+   mini-window or the selected window.  FREEZE_P non-zero means freeze
+   the window start.  */
+
+static void
+freeze_window_start (w, freeze_p)
+     struct window *w;
+     int freeze_p;
+{
+  if (w == XWINDOW (selected_window)
+      || MINI_WINDOW_P (w)
+      || (MINI_WINDOW_P (XWINDOW (selected_window))
+         && w == XWINDOW (Vminibuf_scroll_window)))
+    freeze_p = 0;
+  
+  w->frozen_window_start_p = freeze_p;
+}
+
+
+/* Freeze or unfreeze the window starts of all leaf windows on frame
+   F, except the selected window and a mini-window.  FREEZE_P non-zero
+   means freeze the window start.  */
+
+void
+freeze_window_starts (f, freeze_p)
+     struct frame *f;
+     int freeze_p;
+{
+  foreach_window (f, freeze_window_start, freeze_p);
+}
+
+\f
+/***********************************************************************
+                           Initialization
+ ***********************************************************************/
+
+/* Return 1 if window configurations C1 and C2
+   describe the same state of affairs.  This is used by Fequal.   */
+
+int
+compare_window_configurations (c1, c2, ignore_positions)
+     Lisp_Object c1, c2;
+     int ignore_positions;
+{
+  register struct save_window_data *d1, *d2;
+  struct Lisp_Vector *sw1, *sw2;
+  int i;
+
+  d1 = (struct save_window_data *) XVECTOR (c1);
+  d2 = (struct save_window_data *) XVECTOR (c2);
+  sw1 = XVECTOR (d1->saved_windows);
+  sw2 = XVECTOR (d2->saved_windows);
+
+  if (! EQ (d1->frame_width, d2->frame_width))
+    return 0;
+  if (! EQ (d1->frame_height, d2->frame_height))
+    return 0;
+  if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
+    return 0;
+  if (! EQ (d1->selected_frame, d2->selected_frame))
+    return 0;
+  /* Don't compare the current_window field directly.
+     Instead see w1_is_current and w2_is_current, below.  */
+  if (! EQ (d1->current_buffer, d2->current_buffer))
+    return 0;
+  if (! ignore_positions)
+    if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
+      return 0;
+  /* Don't compare the root_window field.
+     We don't require the two configurations
+     to use the same window object,
+     and the two root windows must be equivalent
+     if everything else compares equal.  */
+  if (! EQ (d1->focus_frame, d2->focus_frame))
+    return 0;
+  if (! EQ (d1->min_width, d2->min_width))
+    return 0;
+  if (! EQ (d1->min_height, d2->min_height))
+    return 0;
+
+  /* Verify that the two confis have the same number of windows.  */
+  if (sw1->size != sw2->size)
+    return 0;
+
+  for (i = 0; i < sw1->size; i++)
+    {
+      struct saved_window *p1, *p2;
+      int w1_is_current, w2_is_current;
+
+      p1 = SAVED_WINDOW_N (sw1, i);
+      p2 = SAVED_WINDOW_N (sw2, i);
+
+      /* Verify that the current windows in the two
+        configurations correspond to each other.  */
+      w1_is_current = EQ (d1->current_window, p1->window);
+      w2_is_current = EQ (d2->current_window, p2->window);
+
+      if (w1_is_current != w2_is_current)
+       return 0;
+
+      /* Verify that the corresponding windows do match.  */
+      if (! EQ (p1->buffer, p2->buffer))
+       return 0;
+      if (! EQ (p1->left, p2->left))
+       return 0;
+      if (! EQ (p1->top, p2->top))
+       return 0;
+      if (! EQ (p1->width, p2->width))
+       return 0;
+      if (! EQ (p1->height, p2->height))
+       return 0;
+      if (! EQ (p1->display_table, p2->display_table))
+       return 0;
+      if (! EQ (p1->parent, p2->parent))
+       return 0;
+      if (! EQ (p1->prev, p2->prev))
+       return 0;
+      if (! ignore_positions)
+       {
+         if (! EQ (p1->hscroll, p2->hscroll))
+           return 0;
+         if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
+           return 0;
+         if (NILP (Fequal (p1->start, p2->start)))
+           return 0;
+         if (NILP (Fequal (p1->pointm, p2->pointm)))
+           return 0;
+         if (NILP (Fequal (p1->mark, p2->mark)))
+           return 0;
+       }
+    }
+
+  return 1;
+}
+
+DEFUN ("compare-window-configurations", Fcompare_window_configurations,
+       Scompare_window_configurations, 2, 2, 0,
+  "Compare two window configurations as regards the structure of windows.\n\
+This function ignores details such as the values of point and mark\n\
+and scrolling positions.")
+  (x, y)
+     Lisp_Object x, y;
+{
+  if (compare_window_configurations (x, y, 1))
+    return Qt;
+  return Qnil;
+}
+\f
+void
 init_window_once ()
 {
-  selected_frame = make_terminal_frame ();
-  XSETFRAME (Vterminal_frame, selected_frame);
-  minibuf_window = selected_frame->minibuffer_window;
-  selected_window = selected_frame->selected_window;
-  last_nonminibuf_frame = selected_frame;
+  struct frame *f = make_terminal_frame ();
+  XSETFRAME (selected_frame, f);
+  Vterminal_frame = selected_frame;
+  minibuf_window = f->minibuffer_window;
+  selected_window = f->selected_window;
+  last_nonminibuf_frame = f;
 
   window_initialized = 1;
 }
 
+void
 syms_of_window ()
 {
+  Qleft_bitmap_area = intern ("left-bitmap-area");
+  staticpro (&Qleft_bitmap_area);
+  Qright_bitmap_area = intern ("right-bitmap-area");
+  staticpro (&Qright_bitmap_area);
+  
+  Qwindow_size_fixed = intern ("window-size-fixed");
+  staticpro (&Qwindow_size_fixed);
+  
   staticpro (&Qwindow_configuration_change_hook);
   Qwindow_configuration_change_hook
     = intern ("window-configuration-change-hook");
@@ -3659,6 +5172,9 @@ syms_of_window ()
   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);
 
@@ -3712,7 +5228,12 @@ There are two ways to use a list as an element:\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'.");
+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,
@@ -3727,7 +5248,12 @@ There are two ways to use a list as an element:\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'.");
+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,
@@ -3790,15 +5316,15 @@ 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,
+  DEFVAR_LISP ("scroll-preserve-screen-position",
+              &Vscroll_preserve_screen_position,
     "*Nonzero means scroll commands move point to keep its screen line unchanged.");
-  scroll_preserve_screen_position = 0;
+  Vscroll_preserve_screen_position = Qnil;
 
   DEFVAR_LISP ("window-configuration-change-hook",
               &Vwindow_configuration_change_hook,
     "Functions to call when window configuration changes.\n\
-The selected frae is the one whose configuration has changed.");
+The selected frame is the one whose configuration has changed.");
   Vwindow_configuration_change_hook = Qnil;
 
   defsubr (&Sselected_window);
@@ -3853,11 +5379,18 @@ The selected frae is the one whose configuration has changed.");
   defsubr (&Srecenter);
   defsubr (&Smove_to_window_line);
   defsubr (&Swindow_configuration_p);
+  defsubr (&Swindow_configuration_frame);
   defsubr (&Sset_window_configuration);
   defsubr (&Scurrent_window_configuration);
   defsubr (&Ssave_window_excursion);
+  defsubr (&Sset_window_margins);
+  defsubr (&Swindow_margins);
+  defsubr (&Swindow_vscroll);
+  defsubr (&Sset_window_vscroll);
+  defsubr (&Scompare_window_configurations);
 }
 
+void
 keys_of_window ()
 {
   initial_define_key (control_x_map, '1', "delete-other-windows");