*** empty log message ***
[bpt/emacs.git] / src / window.c
index a510db6..2340ec6 100644 (file)
@@ -48,10 +48,6 @@ Boston, MA 02111-1307, USA.  */
 #include "macterm.h"
 #endif
 
-#ifndef max
-#define max(a, b) ((a) < (b) ? (b) : (a))
-#endif
-
 /* Values returned from coordinates_in_window.  */
 
 enum window_part
@@ -67,7 +63,7 @@ enum window_part
 
 
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
-Lisp_Object Qwindow_size_fixed, Qleft_fringe, Qright_fringe;
+Lisp_Object Qwindow_size_fixed;
 extern Lisp_Object Qheight, Qwidth;
 
 static int displayed_window_lines P_ ((struct window *));
@@ -83,7 +79,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,
@@ -298,7 +294,7 @@ used by that frame.  */)
 {
   if (NILP (frame))
     frame = selected_frame;
-  CHECK_LIVE_FRAME (frame, 0);
+  CHECK_LIVE_FRAME (frame);
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
 
@@ -335,7 +331,7 @@ POS defaults to point in WINDOW; WINDOW defaults to the selected window.  */)
 
   if (!NILP (pos))
     {
-      CHECK_NUMBER_COERCE_MARKER (pos, 0);
+      CHECK_NUMBER_COERCE_MARKER (pos);
       posint = XINT (pos);
     }
   else if (w == XWINDOW (selected_window))
@@ -386,7 +382,7 @@ decode_window (window)
   if (NILP (window))
     return XWINDOW (selected_window);
 
-  CHECK_LIVE_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window);
   return XWINDOW (window);
 }
 
@@ -434,7 +430,7 @@ NCOL should be zero or positive.  */)
   struct window *w = decode_window (window);
   int hscroll;
 
-  CHECK_NUMBER (ncol, 1);
+  CHECK_NUMBER (ncol);
   hscroll = max (0, XINT (ncol));
   
   /* Prevent redisplay shortcuts when changing the hscroll.  */
@@ -501,7 +497,7 @@ and BOTTOM is one more than the bottommost row used by WINDOW
    if it is on the border between the window and its right sibling,
       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,
+   if it is in left or right fringe of the window,
    return 5 or 6, and convert *X and *Y to window-relative corrdinates.
 
    X and Y are frame relative pixel coordinates.  */
@@ -515,9 +511,8 @@ coordinates_in_window (w, x, y)
      everywhere.  */
   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);
   enum window_part part;
-  int ux = CANON_X_UNIT (f), uy = CANON_Y_UNIT (f);
+  int ux = CANON_X_UNIT (f);
   int x0 = XFASTINT (w->left) * ux;
   int x1 = x0 + XFASTINT (w->width) * ux;
   /* The width of the area where the vertical line can be dragged.
@@ -588,10 +583,10 @@ coordinates_in_window (w, x, y)
   else if (*y < top_y
           || *y >= bottom_y
           || *x < (left_x
-                   - flags_area_width
+                   - FRAME_LEFT_FRINGE_WIDTH (f)
                    - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * ux)
           || *x > (right_x
-                   + flags_area_width
+                   + FRAME_RIGHT_FRINGE_WIDTH (f)
                    + FRAME_RIGHT_SCROLL_BAR_WIDTH (f) * ux))
     {
       part = ON_NOTHING;
@@ -601,13 +596,13 @@ coordinates_in_window (w, x, y)
       if (!w->pseudo_window_p
          && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)
          && !WINDOW_RIGHTMOST_P (w)
-         && (abs (*x - right_x - flags_area_width) < grabbable_width))
+         && (abs (*x - right_x - FRAME_RIGHT_FRINGE_WIDTH (f)) < grabbable_width))
        {
          part = ON_VERTICAL_BORDER;
        }
       else if (*x < left_x || *x > right_x)
        {
-         /* Other lines than the mode line don't include flags areas and
+         /* Other lines than the mode line don't include fringes and
             scroll bars on the left.  */
       
          /* Convert X and Y to window-relative pixel coordinates.  */
@@ -628,7 +623,7 @@ coordinates_in_window (w, x, y)
         terminals, the vertical line's x coordinate is right_x.  */
       if (*x < left_x || *x > right_x)
        {
-         /* Other lines than the mode line don't include flags areas and
+         /* Other lines than the mode line don't include fringes and
             scroll bars on the left.  */
       
          /* Convert X and Y to window-relative pixel coordinates.  */
@@ -669,9 +664,8 @@ If COORDINATES are in the text portion of WINDOW,
    the coordinates relative to the window are returned.
 If they are in the mode line of WINDOW, `mode-line' is returned.
 If they are in the top mode line of WINDOW, `header-line' is returned.
-If they are in the fringe to the left of the window,
-   `left-fringe' is returned, if they are in the area on the right of
-   the window, `right-fringe' 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.  */)
      (coordinates, window)
@@ -682,14 +676,14 @@ If they are on the border between WINDOW and its right sibling,
   int x, y;
   Lisp_Object lx, ly;
 
-  CHECK_LIVE_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window);
   w = XWINDOW (window);
   f = XFRAME (w->frame);
-  CHECK_CONS (coordinates, 1);
+  CHECK_CONS (coordinates);
   lx = Fcar (coordinates);
   ly = Fcdr (coordinates);
-  CHECK_NUMBER_OR_FLOAT (lx, 1);
-  CHECK_NUMBER_OR_FLOAT (ly, 1);
+  CHECK_NUMBER_OR_FLOAT (lx);
+  CHECK_NUMBER_OR_FLOAT (ly);
   x = PIXEL_X_FROM_CANON_X (f, lx);
   y = PIXEL_Y_FROM_CANON_Y (f, ly);
 
@@ -820,12 +814,12 @@ column 0.  */)
 
   if (NILP (frame))
     frame = selected_frame;
-  CHECK_LIVE_FRAME (frame, 2);
+  CHECK_LIVE_FRAME (frame);
   f = XFRAME (frame);
 
   /* Check that arguments are integers or floats.  */
-  CHECK_NUMBER_OR_FLOAT (x, 0);
-  CHECK_NUMBER_OR_FLOAT (y, 1);
+  CHECK_NUMBER_OR_FLOAT (x);
+  CHECK_NUMBER_OR_FLOAT (y);
 
   return window_from_coordinates (f, 
                                  PIXEL_X_FROM_CANON_X (f, x),
@@ -889,7 +883,7 @@ if it isn't already recorded.  */)
   Lisp_Object buf;
 
   buf = w->buffer;
-  CHECK_BUFFER (buf, 0);
+  CHECK_BUFFER (buf);
 
 #if 0 /* This change broke some things.  We should make it later.  */
   /* If we don't know the end position, return nil.
@@ -950,7 +944,7 @@ 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);
+  CHECK_NUMBER_COERCE_MARKER (pos);
   if (w == XWINDOW (selected_window)
       && XBUFFER (w->buffer) == current_buffer)
     Fgoto_char (pos);
@@ -974,7 +968,7 @@ from overriding motion of point in order to display at this exact start.  */)
 {
   register struct window *w = decode_window (window);
 
-  CHECK_NUMBER_COERCE_MARKER (pos, 1);
+  CHECK_NUMBER_COERCE_MARKER (pos);
   set_marker_restricted (w->start, pos, w->buffer);
   /* this is not right, but much easier than doing what is right. */
   w->start_at_line_beg = Qnil;
@@ -1199,7 +1193,7 @@ delete_window (window)
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_WINDOW (window);
   p = XWINDOW (window);
 
   /* It's okay to delete an already-deleted window.  */
@@ -1220,34 +1214,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;
       }
   }
 
@@ -1452,7 +1461,7 @@ decode_next_window_args (window, minibuf, all_frames)
   if (NILP (*window))
     *window = selected_window;
   else
-    CHECK_LIVE_WINDOW (*window, 0);
+    CHECK_LIVE_WINDOW (*window);
   
   /* MINIBUF nil may or may not include minibuffers.  Decide if it
      does.  */
@@ -1636,7 +1645,7 @@ argument ALL_FRAMES is non-nil, cycle through all frames.  */)
   Lisp_Object window;
   int i;
 
-  CHECK_NUMBER (arg, 0);
+  CHECK_NUMBER (arg);
   window = selected_window;
   
   for (i = XINT (arg); i > 0; --i)
@@ -1994,7 +2003,7 @@ value is reasonable when this function is called.  */)
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_LIVE_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window);
   w = XWINDOW (window);
 
   startpos = marker_position (w->start);
@@ -2060,7 +2069,7 @@ If FRAME is a frame, search only that frame.  */)
   if (!NILP (buffer))
     {
       buffer = Fget_buffer (buffer);
-      CHECK_BUFFER (buffer, 0);
+      CHECK_BUFFER (buffer);
       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
     }
   
@@ -2077,7 +2086,7 @@ DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
   if (!NILP (buffer))
     {
       buffer = Fget_buffer (buffer);
-      CHECK_BUFFER (buffer, 0);
+      CHECK_BUFFER (buffer);
       window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
     }
   return Qnil;
@@ -2109,7 +2118,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.  */
@@ -2133,13 +2142,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);
@@ -2378,7 +2386,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)
@@ -2390,6 +2401,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);
   
@@ -2406,12 +2420,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;
@@ -2537,7 +2551,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);
          }
     }
 }
@@ -2664,7 +2678,7 @@ BUFFER can be a buffer or buffer name.  */)
 
   XSETWINDOW (window, w);
   buffer = Fget_buffer (buffer);
-  CHECK_BUFFER (buffer, 1);
+  CHECK_BUFFER (buffer);
 
   if (NILP (XBUFFER (buffer)->name))
     error ("Attempt to display deleted buffer");
@@ -2709,7 +2723,7 @@ select_window_1 (window, recordflag)
   register struct window *ow;
   struct frame *sf;
 
-  CHECK_LIVE_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window);
 
   w = XWINDOW (window);
   w->frozen_window_start_p = 0;
@@ -2806,7 +2820,7 @@ See `special-display-buffer-names', and `special-display-regexps'.  */)
 {
   Lisp_Object tem;
 
-  CHECK_STRING (buffer_name, 1);
+  CHECK_STRING (buffer_name);
 
   tem = Fmember (buffer_name, Vspecial_display_buffer_names);
   if (!NILP (tem))
@@ -2838,7 +2852,7 @@ See `same-window-buffer-names' and `same-window-regexps'.  */)
 {
   Lisp_Object tem;
 
-  CHECK_STRING (buffer_name, 1);
+  CHECK_STRING (buffer_name);
 
   tem = Fmember (buffer_name, Vsame_window_buffer_names);
   if (!NILP (tem))
@@ -2899,7 +2913,7 @@ displayed.  */)
 
   swp = Qnil;
   buffer = Fget_buffer (buffer);
-  CHECK_BUFFER (buffer, 0);
+  CHECK_BUFFER (buffer);
 
   if (!NILP (Vdisplay_buffer_function))
     return call2 (Vdisplay_buffer_function, buffer, not_this_window);
@@ -3049,7 +3063,7 @@ displayed.  */)
                           + XFASTINT (XWINDOW (window)->height));
              enlarge_window (upper,
                              total / 2 - XFASTINT (XWINDOW (upper)->height),
-                             0);
+                             0, 0);
            }
        }
     }
@@ -3169,7 +3183,7 @@ SIZE includes that window's scroll bar, or the divider column to its right.  */)
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_LIVE_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window);
 
   o = XWINDOW (window);
   fo = XFRAME (WINDOW_FRAME (o));
@@ -3187,7 +3201,7 @@ SIZE includes that window's scroll bar, or the divider column to its right.  */)
     }
   else
     {
-      CHECK_NUMBER (size, 1);
+      CHECK_NUMBER (size);
       size_int = XINT (size);
     }
 
@@ -3275,15 +3289,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, 0);
-  enlarge_window (selected_window, XINT (arg), !NILP (side));
+  CHECK_NUMBER (arg);
+  enlarge_window (selected_window, XINT (arg), !NILP (side),
+                 !NILP (preserve_before));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3298,8 +3317,8 @@ Interactively, if an argument is not given, make the window one line smaller.  *
      (arg, side)
      register Lisp_Object arg, side;
 {
-  CHECK_NUMBER (arg, 0);
-  enlarge_window (selected_window, -XINT (arg), !NILP (side));
+  CHECK_NUMBER (arg);
+  enlarge_window (selected_window, -XINT (arg), !NILP (side), 0);
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3331,15 +3350,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;
@@ -3384,16 +3406,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
@@ -3411,16 +3452,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;
@@ -3433,7 +3475,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))
            {
@@ -3457,7 +3500,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),
@@ -3499,11 +3542,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
@@ -3546,19 +3614,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);
@@ -3755,7 +3824,9 @@ grow_mini_window (w, delta)
     {
       int min_height = window_min_size (root, 0, 0, 0);
       if (XFASTINT (root->height) - delta < min_height)
-       delta = XFASTINT (root->height) - min_height;
+       /* Note that the root window may already be smaller than
+          min_height.  */
+       delta = max (0, XFASTINT (root->height) - min_height);
     }
     
   if (delta)
@@ -3803,7 +3874,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);
     }
 }
 
@@ -3878,9 +3949,9 @@ window_internal_width (w)
     width -= 1;
 
   /* On window-systems, areas to the left and right of the window
-     are used to display bitmaps there.  */
+     are used as fringes.  */
   if (FRAME_WINDOW_P (f))
-    width -= FRAME_FLAGS_AREA_COLS (f);
+    width -= FRAME_FRINGE_COLS (f);
 
   return width;
 }
@@ -4351,7 +4422,7 @@ showing that buffer is used.  */)
               && ! EQ (window, selected_window));
     }
 
-  CHECK_LIVE_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window);
 
   if (EQ (window, selected_window))
     error ("There is no other window");
@@ -4396,7 +4467,7 @@ showing that buffer, popping the buffer up if necessary.  */)
     {
       if (CONSP (arg))
        arg = Fcar (arg);
-      CHECK_NUMBER (arg, 0);
+      CHECK_NUMBER (arg);
       window_scroll (window, XINT (arg), 0, 1);
     }
 
@@ -4408,7 +4479,13 @@ showing that buffer, popping the buffer up if necessary.  */)
 \f
 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
        doc: /* Scroll selected window display ARG columns left.
-Default for ARG is window width minus 2.  */)
+Default for ARG is window width minus 2.
+Value is the total amount of leftward horizontal scrolling in
+effect after the change.
+If `automatic-hscrolling' is non-nil, the argument ARG modifies
+a lower bound for automatic scrolling, i.e. automatic scrolling
+will not scroll a window to a column less than the value returned
+by this function.  */)
      (arg)
      register Lisp_Object arg;
 {
@@ -4432,7 +4509,13 @@ Default for ARG is window width minus 2.  */)
 
 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
        doc: /* Scroll selected window display ARG columns right.
-Default for ARG is window width minus 2.  */)
+Default for ARG is window width minus 2.
+Value is the total amount of leftward horizontal scrolling in
+effect after the change.
+If `automatic-hscrolling' is non-nil, the argument ARG modifies
+a lower bound for automatic scrolling, i.e. automatic scrolling
+will not scroll a window to a column less than the value returned
+by this function.  */)
      (arg)
      register Lisp_Object arg;
 {
@@ -4522,6 +4605,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;
@@ -4539,7 +4625,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
   else
     {
       arg = Fprefix_numeric_value (arg);
-      CHECK_NUMBER (arg, 0);
+      CHECK_NUMBER (arg);
     }
 
   set_buffer_internal (buf);
@@ -4576,18 +4662,17 @@ and redisplay normally--don't erase and redraw the frame.  */)
          nlines = - XINT (arg) - 1;
          move_it_by_lines (&it, nlines, 1);
 
-         y1 = it.current_y - y0;
-         h = line_bottom_y (&it) - y1;
+         y1 = line_bottom_y (&it);
 
          /* If we can't move down NLINES lines because we hit
             the end of the buffer, count in some empty lines.  */
          if (it.vpos < nlines)
            y1 += (nlines - it.vpos) * CANON_Y_UNIT (it.f);
          
-         y0 = it.last_visible_y - y1 - h;
-         
+         h = window_box_height (w) - (y1 - y0);
+
          start_display (&it, w, pt);
-         move_it_vertically (&it, - y0);
+         move_it_vertically (&it, - h);
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
        }
@@ -5261,7 +5346,7 @@ redirection (see `redirect-frame-focus').  */)
 
   if (NILP (frame))
     frame = selected_frame;
-  CHECK_LIVE_FRAME (frame, 0);
+  CHECK_LIVE_FRAME (frame);
   f = XFRAME (frame);
 
   n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
@@ -5330,9 +5415,9 @@ A nil width parameter means no margin.  */)
   struct window *w = decode_window (window);
 
   if (!NILP (left))
-    CHECK_NUMBER_OR_FLOAT (left, 1);
+    CHECK_NUMBER_OR_FLOAT (left);
   if (!NILP (right))
-    CHECK_NUMBER_OR_FLOAT (right, 2);
+    CHECK_NUMBER_OR_FLOAT (right);
 
   /* Check widths < 0 and translate a zero width to nil.
      Margins that are too wide have to be checked elsewhere.  */
@@ -5391,7 +5476,7 @@ Value is a multiple of the canonical character height of WINDOW.  */)
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_WINDOW (window);
   w = XWINDOW (window);
   f = XFRAME (w->frame);
   
@@ -5406,8 +5491,8 @@ Value is a multiple of the canonical character height of WINDOW.  */)
 DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
        2, 2, 0,
        doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
-WINDOW nil or omitted means use the selected window.  VSCROLL is a
-non-negative multiple of the canonical character height of WINDOW.  */)
+WINDOW nil means use the selected window.  VSCROLL is a non-negative
+multiple of the canonical character height of WINDOW.  */)
      (window, vscroll)
      Lisp_Object window, vscroll;
 {
@@ -5417,8 +5502,8 @@ non-negative multiple of the canonical character height of WINDOW.  */)
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
-  CHECK_NUMBER_OR_FLOAT (vscroll, 1);
+    CHECK_WINDOW (window);
+  CHECK_NUMBER_OR_FLOAT (vscroll);
   
   w = XWINDOW (window);
   f = XFRAME (w->frame);
@@ -5665,11 +5750,6 @@ init_window ()
 void
 syms_of_window ()
 {
-  Qleft_fringe = intern ("left-fringe");
-  staticpro (&Qleft_fringe);
-  Qright_fringe = intern ("right-fringe");
-  staticpro (&Qright_fringe);
-  
   Qwindow_size_fixed = intern ("window-size-fixed");
   staticpro (&Qwindow_size_fixed);