]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Use macro SPECPDL_INDEX.
[gnu-emacs] / src / window.c
index 6ee3086d616cba7b1d3cf93f5c464c5febfa3782..0bacf5fd549a5be16945e3ddfa533da2523bfcfc 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,97,1998,2000, 2001
+   Copyright (C) 1985,86,87,93,94,95,96,97,1998,2000, 2001, 2002
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -44,7 +44,7 @@ Boston, MA 02111-1307, USA.  */
 #ifdef MSDOS
 #include "msdos.h"
 #endif
-#ifdef macintosh
+#ifdef MAC_OS
 #include "macterm.h"
 #endif
 
@@ -58,12 +58,15 @@ enum window_part
   ON_VERTICAL_BORDER,
   ON_HEADER_LINE,
   ON_LEFT_FRINGE,
-  ON_RIGHT_FRINGE
+  ON_RIGHT_FRINGE,
+  ON_LEFT_MARGIN,
+  ON_RIGHT_MARGIN
 };
 
 
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
 Lisp_Object Qwindow_size_fixed;
+extern Lisp_Object Qleft_margin, Qright_margin;
 extern Lisp_Object Qheight, Qwidth;
 
 static int displayed_window_lines P_ ((struct window *));
@@ -79,7 +82,7 @@ static int window_min_size P_ ((struct window *, int, int, int *));
 static void size_window P_ ((Lisp_Object, int, int, int));
 static int freeze_window_start P_ ((struct window *, void *));
 static int window_fixed_size_p P_ ((struct window *, int, int));
-static void enlarge_window P_ ((Lisp_Object, int, int));
+static void enlarge_window P_ ((Lisp_Object, int, int, int));
 static Lisp_Object window_list P_ ((void));
 static int add_window_to_list P_ ((struct window *, void *));
 static int candidate_window_p P_ ((Lisp_Object, Lisp_Object, Lisp_Object,
@@ -120,6 +123,11 @@ Lisp_Object Vwindow_list;
 
 Lisp_Object minibuf_window;
 
+/* Non-nil means it is the window whose mode line should be
+   shown as the selected window when the minibuffer is selected.  */
+
+Lisp_Object minibuf_selected_window;
+
 /* Non-nil means it is the window for C-M-v to scroll
    when the mini-buffer is selected.  */
 
@@ -133,10 +141,15 @@ Lisp_Object Vother_window_scroll_buffer;
 
 Lisp_Object Vtemp_buffer_show_function;
 
+/* Non-zero means to use mode-line-inactive face in all windows but the
+   selected-window and the minibuffer-scroll-window when the
+   minibuffer is active.  */
+int mode_line_in_non_selected_windows;
+
 /* If a window gets smaller than either of these, it is removed. */
 
-int window_min_height;
-int window_min_width;
+EMACS_INT window_min_height;
+EMACS_INT window_min_width;
 
 /* Nonzero implies Fdisplay_buffer should create windows. */
 
@@ -189,11 +202,11 @@ 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;
+EMACS_INT split_height_threshold;
 
 /* Number of lines of continuity in scrolling by screenfuls.  */
 
-int next_screen_context_lines;
+EMACS_INT next_screen_context_lines;
 
 /* Incremented for each window created.  */
 
@@ -218,7 +231,7 @@ Lisp_Object Vscroll_preserve_screen_position;
 static int inhibit_frame_unsplittable;
 #endif /* 0 */
 
-extern int scroll_margin;
+extern EMACS_INT scroll_margin;
 
 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
 \f
@@ -265,6 +278,7 @@ make_window ()
   bzero (&p->phys_cursor, sizeof (p->phys_cursor));
   p->desired_matrix = p->current_matrix = 0;
   p->phys_cursor_type = -1;
+  p->phys_cursor_width = -1;
   p->must_be_updated_p = 0;
   XSETFASTINT (p->window_end_vpos, 0);
   XSETFASTINT (p->window_end_pos, 0);
@@ -273,6 +287,8 @@ make_window ()
   XSETWINDOW (val, p);
   XSETFASTINT (p->last_point, 0);
   p->frozen_window_start_p = 0;
+  p->height_fixed_p = 0;
+  p->last_cursor_off_p = p->cursor_off_p = 0;
 
   Vwindow_list = Qnil;
   return val;
@@ -423,7 +439,10 @@ DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
 
 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0,
        doc: /* Set number of columns WINDOW is scrolled from left margin to NCOL.
-NCOL should be zero or positive.  */)
+NCOL should be zero or positive.
+
+Note that if `automatic-hscrolling' is non-nil, you cannot scroll the
+window so that the location of point becomes invisible.  */)
      (window, ncol)
      Lisp_Object window, ncol;
 {
@@ -498,7 +517,9 @@ and BOTTOM is one more than the bottommost row used by WINDOW
       return 3.
    if it is on the window's top line, return 4;
    if it is in left or right fringe of the window,
-   return 5 or 6, and convert *X and *Y to window-relative corrdinates.
+   return 5 or 6, and convert *X and *Y to window-relative coordinates;
+   if it is in the marginal area to the left/right of the window,
+   return 7 or 8, and convert *X and *Y to window-relative coordinates.
 
    X and Y are frame relative pixel coordinates.  */
 
@@ -518,6 +539,7 @@ coordinates_in_window (w, x, y)
   /* The width of the area where the vertical line can be dragged.
      (Between mode lines for instance.  */
   int grabbable_width = ux;
+  int lmargin_width = 0, rmargin_width = 0;
 
   if (*x < x0 || *x >= x1)
     return ON_NOTHING;
@@ -612,9 +634,21 @@ coordinates_in_window (w, x, y)
        }
       else
        {
-         *x -= left_x;
-         *y -= top_y;
-         part = ON_TEXT;
+         lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
+         rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
+         /* You can never be on a margin area if its width is zero.  */
+         if (lmargin_width
+             && *x <= window_box_right (w, LEFT_MARGIN_AREA))
+           part = ON_LEFT_MARGIN;
+         else if (rmargin_width
+                  && *x >= window_box_left (w, RIGHT_MARGIN_AREA))
+           part = ON_RIGHT_MARGIN;
+         else
+           {
+             part = ON_TEXT;
+             *x -= left_x;
+             *y -= top_y;
+           }
        }
     }
   else
@@ -642,10 +676,23 @@ coordinates_in_window (w, x, y)
        }
       else
        {
-         /* Convert X and Y to window-relative pixel coordinates.  */
-         *x -= left_x;
-         *y -= top_y;
-         part = ON_TEXT;
+         lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
+         rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
+         /* You can never be on a margin area if its width is zero.
+            This is especially important for character terminals.  */
+         if (lmargin_width
+             && *x <= window_box_right (w, LEFT_MARGIN_AREA))
+           part = ON_LEFT_MARGIN;
+         else if (rmargin_width
+                  && *x >= window_box_left (w, RIGHT_MARGIN_AREA))
+           part = ON_RIGHT_MARGIN;
+         else
+           {
+             part = ON_TEXT;
+             /* Convert X and Y to window-relative pixel coordinates.  */
+             *x -= left_x;
+             *y -= top_y;
+           }
        }
     }
 
@@ -667,7 +714,9 @@ If they are in the top mode line of WINDOW, `header-line' is returned.
 If they are in the left fringe of WINDOW, `left-fringe' is returned.
 If they are in the right fringe of WINDOW, `right-fringe' is returned.
 If they are on the border between WINDOW and its right sibling,
-  `vertical-line' is returned.  */)
+  `vertical-line' is returned.
+If they are in the windows's left or right marginal areas, `left-margin'\n\
+  or `right-margin' is returned.  */)
      (coordinates, window)
      register Lisp_Object coordinates, window;
 {
@@ -713,6 +762,12 @@ If they are on the border between WINDOW and its right sibling,
     case ON_RIGHT_FRINGE:
       return Qright_fringe;
 
+    case ON_LEFT_MARGIN:
+      return Qleft_margin;
+      
+    case ON_RIGHT_MARGIN:
+      return Qright_margin;
+
     default:
       abort ();
     }
@@ -903,7 +958,7 @@ if it isn't already recorded.  */)
       struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
 
       /* In case W->start is out of the range, use something
-         reasonable.  This situation occured when loading a file with
+         reasonable.  This situation occurred 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.  */
@@ -1134,6 +1189,7 @@ replace_window (old, replacement)
   bzero (&p->last_cursor, sizeof (p->last_cursor));
   bzero (&p->phys_cursor, sizeof (p->phys_cursor));
   p->phys_cursor_type = -1;
+  p->phys_cursor_width = -1;
   p->must_be_updated_p = 0;
   p->pseudo_window_p = 0;
   XSETFASTINT (p->window_end_vpos, 0);
@@ -1214,34 +1270,49 @@ delete_window (window)
 
   /* Are we trying to delete any frame's selected window?  */
   {
-    Lisp_Object pwindow;
+    Lisp_Object swindow, pwindow;
 
     /* See if the frame's selected window is either WINDOW
        or any subwindow of it, by finding all that window's parents
        and comparing each one with WINDOW.  */
-    pwindow = FRAME_SELECTED_WINDOW (f);
+    swindow = FRAME_SELECTED_WINDOW (f);
 
-    while (!NILP (pwindow))
+    while (1)
       {
-       if (EQ (window, pwindow))
+       pwindow = swindow;
+       while (!NILP (pwindow))
+         {
+           if (EQ (window, pwindow))
+             break;
+           pwindow = XWINDOW (pwindow)->parent;
+         }
+
+       /* If the window being deleted is not a parent of SWINDOW,
+          then SWINDOW is ok as the new selected window.  */
+       if (!EQ (window, pwindow))
          break;
-       pwindow = XWINDOW (pwindow)->parent;
+       /* Otherwise, try another window for SWINDOW.  */
+       swindow = Fnext_window (swindow, Qlambda, Qnil);;
+
+       /* If we get back to the frame's selected window,
+          it means there was no acceptable alternative,
+          so we cannot delete.  */
+       if (EQ (swindow, FRAME_SELECTED_WINDOW (f)))
+         error ("Cannot delete window");
       }
 
-    if (EQ (window, pwindow))
+    /* If we need to change SWINDOW, do it.  */
+    if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
       {
-       Lisp_Object alternative;
-       alternative = Fnext_window (window, Qlambda, Qnil);
-
        /* If we're about to delete the selected window on the
           selected frame, then we should use Fselect_window to select
           the new window.  On the other hand, if we're about to
           delete the selected window on any other frame, we shouldn't do
           anything but set the frame's selected_window slot.  */
-       if (EQ (window, selected_window))
-         Fselect_window (alternative);
+       if (EQ (FRAME_SELECTED_WINDOW (f), selected_window))
+         Fselect_window (swindow);
        else
-         FRAME_SELECTED_WINDOW (f) = alternative;
+         FRAME_SELECTED_WINDOW (f) = swindow;
       }
   }
 
@@ -2103,7 +2174,7 @@ replace_buffer_in_all_windows (buffer)
    might crash Emacs.  */
 
 #define MIN_SAFE_WINDOW_WIDTH  (2)
-#define MIN_SAFE_WINDOW_HEIGHT (2)
+#define MIN_SAFE_WINDOW_HEIGHT (1)
 
 /* Make sure that window_min_height and window_min_width are
    not too small; if they are, set them to safe minima.  */
@@ -2127,13 +2198,12 @@ check_frame_size (frame, rows, cols)
      int *rows, *cols;
 {
   /* For height, we have to see:
-     whether the frame has a minibuffer,
-     whether it wants a mode line, and
-     whether it has a menu bar.  */
-  int min_height =
-    (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);
+     how many windows the frame has at minimum (one or two),
+     and whether it has a menu bar or other special stuff at the top.  */
+  int min_height
+    = ((FRAME_MINIBUF_ONLY_P (frame) || ! FRAME_HAS_MINIBUF_P (frame))
+       ? MIN_SAFE_WINDOW_HEIGHT
+       : 2 * MIN_SAFE_WINDOW_HEIGHT);
   
   if (FRAME_TOP_MARGIN (frame) > 0)
     min_height += FRAME_TOP_MARGIN (frame);
@@ -2372,7 +2442,10 @@ window_min_size (w, width_p, ignore_fixed_p, fixed)
    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.  */
+   that become too small unless NODELETE_P is non-zero.
+
+   If NODELETE_P is 2, that means we do delete windows that are
+   too small, even if they were too small before!  */
 
 static void
 size_window (window, size, width_p, nodelete_p)
@@ -2384,6 +2457,9 @@ size_window (window, size, width_p, nodelete_p)
   Lisp_Object child, *forward, *sideward;
   int old_size, min_size;
 
+  if (nodelete_p == 2)
+    nodelete_p = 0;
+
   check_min_window_sizes ();
   size = max (0, size);
   
@@ -2400,12 +2476,12 @@ size_window (window, size, width_p, nodelete_p)
       old_size = XINT (w->height);
       min_size = window_min_height;
     }
-  
-  if (old_size < min_size)
+
+  if (old_size < min_size && nodelete_p != 2)
     w->too_small_ok = Qt;
 
   /* Maybe delete WINDOW if it's too small.  */
-  if (!nodelete_p && !NILP (w->parent))
+  if (nodelete_p != 1 && !NILP (w->parent))
     {
       if (!MINI_WINDOW_P (w) && !NILP (w->too_small_ok))
        min_size = width_p ? MIN_SAFE_WINDOW_WIDTH : MIN_SAFE_WINDOW_HEIGHT;
@@ -2531,7 +2607,7 @@ size_window (window, size, width_p, nodelete_p)
            int child_size;
            c = XWINDOW (child);
            child_size = width_p ? XINT (c->width) : XINT (c->height);
-           size_window (child, child_size, width_p, 0);
+           size_window (child, child_size, width_p, 2);
          }
     }
 }
@@ -2588,7 +2664,7 @@ set_window_buffer (window, buffer, run_hooks_p)
 {
   struct window *w = XWINDOW (window);
   struct buffer *b = XBUFFER (buffer);
-  int count = specpdl_ptr - specpdl;
+  int count = SPECPDL_INDEX ();
 
   w->buffer = buffer;
 
@@ -2866,7 +2942,7 @@ unless the window is the selected window and the optional second
 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).
 If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.
 Returns the window displaying BUFFER.
-If `display-reuse-frames' is non-nil, and another frame is currently
+If `display-buffer-reuse-frames' is non-nil, and another frame is currently
 displaying BUFFER, then simply raise that frame.
 
 The variables `special-display-buffer-names', `special-display-regexps',
@@ -2914,7 +2990,7 @@ displayed.  */)
        }
     }
 
-  /* If the user wants pop-up-frames or display-reuse-frames, then
+  /* If the user wants pop-up-frames or display-buffer-reuse-frames,
      look for a window showing BUFFER on any visible or iconified frame.
      Otherwise search only the current frame.  */
   if (! NILP (frame))
@@ -3043,7 +3119,7 @@ displayed.  */)
                           + XFASTINT (XWINDOW (window)->height));
              enlarge_window (upper,
                              total / 2 - XFASTINT (XWINDOW (upper)->height),
-                             0);
+                             0, 0);
            }
        }
     }
@@ -3098,7 +3174,7 @@ temp_output_buffer_show (buf)
              tem = Fsymbol_value (Qtemp_buffer_show_hook);
              if (!NILP (tem))
                {
-                 int count = specpdl_ptr - specpdl;
+                 int count = SPECPDL_INDEX ();
                  Lisp_Object prev_window;
                  prev_window = selected_window;
 
@@ -3269,15 +3345,20 @@ SIZE includes that window's scroll bar, or the divider column to its right.  */)
   return new;
 }
 \f
-DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p",
+DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p",
        doc: /* Make current window ARG lines bigger.
 From program, optional second arg non-nil means grow sideways ARG columns.
-Interactively, if an argument is not given, make the window one line bigger.  */)
-     (arg, side)
-     register Lisp_Object arg, side;
+Interactively, if an argument is not given, make the window one line bigger.
+
+Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
+of the siblings above or to the left of the selected window.  Only
+siblings to the right or below are changed.  */)
+     (arg, side, preserve_before)
+     register Lisp_Object arg, side, preserve_before;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, XINT (arg), !NILP (side));
+  enlarge_window (selected_window, XINT (arg), !NILP (side),
+                 !NILP (preserve_before));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3293,7 +3374,7 @@ Interactively, if an argument is not given, make the window one line smaller.  *
      register Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, -XINT (arg), !NILP (side));
+  enlarge_window (selected_window, -XINT (arg), !NILP (side), 0);
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3325,15 +3406,18 @@ window_width (window)
   *(widthflag ? &(XWINDOW (w)->width) : &(XWINDOW (w)->height))
 
 
-/* Enlarge selected_window by DELTA.  WIDTHFLAG non-zero means
+/* Enlarge 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.  */
+   fulfill the size request.  If they become too small in the process,
+   they will be deleted.
+
+   If PRESERVE_BEFORE is nonzero, that means don't alter
+   the siblings to the left or above WINDOW.  */
 
 static void
-enlarge_window (window, delta, widthflag)
+enlarge_window (window, delta, widthflag, preserve_before)
      Lisp_Object window;
-     int delta, widthflag;
+     int delta, widthflag, preserve_before;
 {
   Lisp_Object parent, next, prev;
   struct window *p;
@@ -3378,16 +3462,35 @@ enlarge_window (window, delta, widthflag)
   {
     register int maxdelta;
 
-    maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
-               : !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));
+    /* Compute the maximum size increment this window can have.  */
+
+    if (preserve_before)
+      {
+       if (!NILP (parent))
+         {
+           maxdelta = (*sizefun) (parent) - XINT (*sizep);
+           /* Subtract size of siblings before, since we can't take that.  */
+           maxdelta -= XINT (CURBEG (window)) - XINT (CURBEG (parent));
+         }
+       else
+         maxdelta = (!NILP (p->next) ? ((*sizefun) (p->next)
+                                        - window_min_size (XWINDOW (p->next),
+                                                           widthflag, 0, 0))
+                     : (delta = 0));
+      }
+    else
+      maxdelta = (!NILP (parent) ? (*sizefun) (parent) - XINT (*sizep)
+                 /* This is a main window followed by a minibuffer.  */
+                 : !NILP (p->next) ? ((*sizefun) (p->next)
+                                      - window_min_size (XWINDOW (p->next),
+                                                         widthflag, 0, 0))
+                 /* This is a minibuffer following a main window.  */
+                 : !NILP (p->prev) ? ((*sizefun) (p->prev)
+                                      - window_min_size (XWINDOW (p->prev),
+                                                         widthflag, 0, 0))
+                 /* This is a frame with only one window, a minibuffer-only
+                    or a minibufferless frame.  */
+                 : (delta = 0));
 
     if (delta > maxdelta)
       /* This case traps trying to make the minibuffer
@@ -3405,16 +3508,17 @@ enlarge_window (window, delta, widthflag)
   if (delta == 0)
     return;
 
-  /* Find the total we can get from other siblings.  */
+  /* Find the total we can get from other siblings without deleting them.  */
   maximum = 0;
   for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
     maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
                                                    widthflag, 0, 0);
-  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
-    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
-                                                   widthflag, 0, 0);
+  if (! preserve_before)
+    for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+      maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+                                                     widthflag, 0, 0);
 
-  /* If we can get it all from them, do so.  */
+  /* If we can get it all from them without deleting them, do so.  */
   if (delta <= maximum)
     {
       Lisp_Object first_unaffected;
@@ -3427,7 +3531,8 @@ enlarge_window (window, 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 && (!NILP (next) || !NILP (prev)))
+      while (delta != 0
+            && (!NILP (next) || (!preserve_before && !NILP (prev))))
        {
          if (! NILP (next))
            {
@@ -3451,7 +3556,7 @@ enlarge_window (window, delta, widthflag)
          if (delta == 0)
            break;
          
-         if (! NILP (prev))
+         if (!preserve_before && ! NILP (prev))
            {
              int this_one = ((*sizefun) (prev)
                              - window_min_size (XWINDOW (prev),
@@ -3493,11 +3598,36 @@ enlarge_window (window, delta, widthflag)
       register int delta1;
       register int opht = (*sizefun) (parent);
 
-      /* If trying to grow this window to or beyond size of the parent,
-        make delta1 so big that, on shrinking back down,
-        all the siblings end up with less than one line and are deleted.  */
       if (opht <= XINT (*sizep) + delta)
-       delta1 = opht * opht * 2;
+       {
+         /* If trying to grow this window to or beyond size of the parent,
+            just delete all the sibling windows.  */
+         Lisp_Object start, tem, next;
+
+         start = XWINDOW (parent)->vchild;
+         if (NILP (start))
+           start = XWINDOW (parent)->hchild;
+
+         /* Delete any siblings that come after WINDOW.  */
+         tem = XWINDOW (window)->next;
+         while (! NILP (tem))
+           {
+             next = XWINDOW (tem)->next;
+             delete_window (tem);
+             tem = next;
+           }
+
+         /* Delete any siblings that come after WINDOW.
+            Note that if START is not WINDOW, then WINDOW still
+            Fhas siblings, so WINDOW has not yet replaced its parent.  */
+         tem = start;
+         while (! EQ (tem, window))
+           {
+             next = XWINDOW (tem)->next;
+             delete_window (tem);
+             tem = next;
+           }
+       }
       else
        {
          /* Otherwise, make delta1 just right so that if we add
@@ -3540,19 +3670,20 @@ enlarge_window (window, delta, widthflag)
              ++n;
 
          delta1 = n * delta;
-       }
 
-      /* Add delta1 lines or columns to this window, and to the parent,
-        keeping things consistent while not affecting siblings.  */
-      XSETINT (CURSIZE (parent), opht + delta1);
-      (*setsizefun) (window, XINT (*sizep) + delta1, 0);
-
-      /* Squeeze out delta1 lines or columns from our parent,
-        shriking this window and siblings proportionately.
-        This brings parent back to correct size.
-        Delta1 was calculated so this makes this window the desired size,
-        taking it all out of the siblings.  */
-      (*setsizefun) (parent, opht, 0);
+         /* Add delta1 lines or columns to this window, and to the parent,
+            keeping things consistent while not affecting siblings.  */
+         XSETINT (CURSIZE (parent), opht + delta1);
+         (*setsizefun) (window, XINT (*sizep) + delta1, 0);
+
+         /* Squeeze out delta1 lines or columns from our parent,
+            shriking this window and siblings proportionately.
+            This brings parent back to correct size.
+            Delta1 was calculated so this makes this window the desired size,
+            taking it all out of the siblings.  */
+         (*setsizefun) (parent, opht, 0);
+
+       }
     }
 
   XSETFASTINT (p->last_modified, 0);
@@ -3799,7 +3930,7 @@ shrink_mini_window (w)
         among the other windows.  */
       Lisp_Object window;
       XSETWINDOW (window, w);
-      enlarge_window (window, 1 - XFASTINT (w->height), 0);
+      enlarge_window (window, 1 - XFASTINT (w->height), 0, 0);
     }
 }
 
@@ -4034,10 +4165,14 @@ window_scroll_pixel_based (window, n, whole, noerror)
 
   if (! vscrolled)
     {
+      int pos = IT_CHARPOS (it);
+      int bytepos;
       /* Set the window start, and set up the window for redisplay.  */
-      set_marker_restricted (w->start, make_number (IT_CHARPOS (it)),
+      set_marker_restricted (w->start, make_number (pos),
                             w->buffer);
-      w->start_at_line_beg = Fbolp ();
+      bytepos = XMARKER (w->start)->bytepos;
+      w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n')
+                             ? Qt : Qnil);
       w->update_mode_line = Qt;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
@@ -4067,7 +4202,12 @@ window_scroll_pixel_based (window, n, whole, noerror)
             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);
+           {
+             int prev = it.current_y;
+             move_it_by_lines (&it, 1, 1);
+             if (prev == it.current_y)
+               break;
+           }
          SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
        }
       else if (n < 0)
@@ -4258,7 +4398,7 @@ scroll_command (n, direction)
      Lisp_Object n;
      int direction;
 {
-  int count = BINDING_STACK_SIZE ();
+  int count = SPECPDL_INDEX ();
 
   xassert (abs (direction) == 1);
 
@@ -4372,7 +4512,7 @@ showing that buffer, popping the buffer up if necessary.  */)
 {
   Lisp_Object window;
   struct window *w;
-  int count = BINDING_STACK_SIZE ();
+  int count = SPECPDL_INDEX ();
 
   window = Fother_window_for_scrolling ();
   w = XWINDOW (window);
@@ -4462,6 +4602,20 @@ by this function.  */)
   return result;
 }
 
+DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, Sminibuffer_selected_window, 0, 0, 0,
+       doc: /* Return the window which was selected when entering the minibuffer.
+Returns nil, if current window is not a minibuffer window.  */)
+     ()
+{
+  if (minibuf_level > 0
+      && MINI_WINDOW_P (XWINDOW (selected_window))
+      && !NILP (minibuf_selected_window)
+      && WINDOW_LIVE_P (minibuf_selected_window))
+    return minibuf_selected_window;
+
+  return Qnil;
+}
+
 /* Value is the number of lines actually displayed in window W,
    as opposed to its height.  */
 
@@ -4530,6 +4684,9 @@ and redisplay normally--don't erase and redraw the frame.  */)
   int center_p = 0;
   int charpos, bytepos;
 
+  /* If redisplay is suppressed due to an error, try again.  */
+  obuf->display_error_modiff = 0;
+
   if (NILP (arg))
     {
       int i;
@@ -4624,7 +4781,9 @@ and redisplay normally--don't erase and redraw the frame.  */)
   /* Set the new window start.  */
   set_marker_both (w->start, w->buffer, charpos, bytepos);
   w->window_end_valid = Qnil;
-  w->force_start = Qt;
+  
+  w->optional_new_start = Qt;
+
   if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
     w->start_at_line_beg = Qt;
   else
@@ -4710,6 +4869,7 @@ struct save_window_data
     Lisp_Object current_window;
     Lisp_Object current_buffer;
     Lisp_Object minibuf_scroll_window;
+    Lisp_Object minibuf_selected_window;
     Lisp_Object root_window;
     Lisp_Object focus_frame;
     /* Record the values of window-min-width and window-min-height
@@ -4795,10 +4955,7 @@ the return value is nil.  Otherwise the value is t.  */)
   if (NILP (XBUFFER (new_current_buffer)->name))
     new_current_buffer = Qnil;
   else
-    {
-      if (XBUFFER (new_current_buffer) == current_buffer)
-       old_point = PT;
-    }
+    old_point = BUF_PT (XBUFFER (new_current_buffer));
 
   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
   f = XFRAME (frame);
@@ -4950,8 +5107,8 @@ the return value is nil.  Otherwise the value is t.  */)
                               p->mark, w->buffer);
 
                  /* As documented in Fcurrent_window_configuration, don't
-                    save the location of point in the buffer which was current
-                    when the window configuration was recorded.  */
+                    restore the location of point in the buffer which was
+                    current when the window configuration was recorded.  */
                  if (!EQ (p->buffer, new_current_buffer)
                      && XBUFFER (p->buffer) == current_buffer)
                    Fgoto_char (w->pointm);
@@ -4986,9 +5143,15 @@ the return value is nil.  Otherwise the value is t.  */)
       FRAME_ROOT_WINDOW (f) = data->root_window;
       /* Prevent "swapping out point" in the old selected window
         using the buffer that has been restored into it.
-        That swapping out has already been done,
-        near the beginning of this function.  */
+        Use the point value from the beginning of this function
+        since unshow_buffer (called from delete_all_subwindows)
+        could have altered it.  */
       selected_window = Qnil;
+      if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
+       set_marker_restricted (XWINDOW (data->current_window)->pointm,
+                              make_number (old_point),
+                              XWINDOW (data->current_window)->buffer);
+                 
       Fselect_window (data->current_window);
       XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
        = selected_window;
@@ -5034,11 +5197,6 @@ the return value is nil.  Otherwise the value is t.  */)
          else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
            ++n;
        }
-
-      /* If more than one window shows the new and old current buffer,
-        don't try to preserve point in that buffer.  */
-      if (old_point > 0 && n > 1)
-       old_point = -1;
       
       adjust_glyphs (f);
 
@@ -5058,21 +5216,14 @@ the return value is nil.  Otherwise the value is t.  */)
     }
 
   if (!NILP (new_current_buffer))
-    {
-      Fset_buffer (new_current_buffer);
-
-      /* If the buffer that is current now is the same
-        that was current before setting the window configuration,
-        don't alter its PT.  */
-      if (old_point >= 0)
-       SET_PT (old_point);
-    }
+    Fset_buffer (new_current_buffer);
 
   /* Restore the minimum heights recorded in the configuration.  */
   window_min_height = XINT (data->min_height);
   window_min_width = XINT (data->min_width);
 
   Vminibuf_scroll_window = data->minibuf_scroll_window;
+  minibuf_selected_window = data->minibuf_selected_window;
 
   return (FRAME_LIVE_P (f) ? Qt : Qnil);
 }
@@ -5282,7 +5433,8 @@ redirection (see `redirect-frame-focus').  */)
   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;
+  data->minibuf_scroll_window = minibuf_level > 0 ? Vminibuf_scroll_window : Qnil;
+  data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window : Qnil;
   data->root_window = FRAME_ROOT_WINDOW (f);
   data->focus_frame = FRAME_FOCUS_FRAME (f);
   XSETINT (data->min_height, window_min_height);
@@ -5310,7 +5462,7 @@ usage: (save-window-excursion BODY ...)  */)
      Lisp_Object args;
 {
   register Lisp_Object val;
-  register int count = specpdl_ptr - specpdl;
+  register int count = SPECPDL_INDEX ();
 
   record_unwind_protect (Fset_window_configuration,
                         Fcurrent_window_configuration (Qnil));
@@ -5566,8 +5718,12 @@ compare_window_configurations (c1, c2, ignore_positions)
   if (! EQ (d1->current_buffer, d2->current_buffer))
     return 0;
   if (! ignore_positions)
-    if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
-      return 0;
+    {
+      if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
+       return 0;
+      if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
+       return 0;
+    }
   /* Don't compare the root_window field.
      We don't require the two configurations
      to use the same window object,
@@ -5693,6 +5849,9 @@ syms_of_window ()
 
   staticpro (&Vwindow_list);
 
+  minibuf_selected_window = Qnil;
+  staticpro (&minibuf_selected_window);
+
   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
               doc: /* Non-nil means call as function to display a help buffer.
 The function is called with one argument, the buffer to be displayed.
@@ -5718,6 +5877,12 @@ If nil, `display-buffer' will leave the window configuration alone.  */);
               doc: /* Non-nil means it is the window that C-M-v in minibuffer should scroll.  */);
   Vminibuf_scroll_window = Qnil;
 
+  DEFVAR_BOOL ("mode-line-in-non-selected-windows", &mode_line_in_non_selected_windows,
+              doc: /* Non-nil means to use `mode-line-inactive' face in non-selected windows.
+If the minibuffer is active, the `minibuffer-scroll-window' mode line
+is displayed in the `mode-line' face.  */);
+  mode_line_in_non_selected_windows = 1;
+
   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
               doc: /* If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.  */);
   Vother_window_scroll_buffer = Qnil;
@@ -5906,6 +6071,7 @@ This variable automatically becomes buffer-local when set.  */);
   defsubr (&Sscroll_right);
   defsubr (&Sother_window_for_scrolling);
   defsubr (&Sscroll_other_window);
+  defsubr (&Sminibuffer_selected_window);
   defsubr (&Srecenter);
   defsubr (&Swindow_text_height);
   defsubr (&Smove_to_window_line);