(Fwindow_end): Don't call temp_set_pt_both with
[bpt/emacs.git] / src / window.c
index 5c0abd6..dc01b2f 100644 (file)
@@ -43,7 +43,7 @@ Boston, MA 02111-1307, USA.  */
 
 
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
-Lisp_Object Qfixed_window_size;
+Lisp_Object Qwindow_size_fixed, Qleft_bitmap_area, Qright_bitmap_area;
 extern Lisp_Object Qheight, Qwidth;
 
 static struct window *decode_window P_ ((Lisp_Object));
@@ -54,9 +54,13 @@ 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 *));
-static int window_fixed_size_p P_ ((struct window *, int, 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));
 
 
 /* This is the window in which the terminal's cursor should
@@ -207,6 +211,7 @@ make_window ()
   XSETFASTINT (p->height, 0);
   XSETFASTINT (p->width, 0);
   XSETFASTINT (p->hscroll, 0);
+  p->orig_top = p->orig_height = Qnil;
   p->start = Fmake_marker ();
   p->pointm = Fmake_marker ();
   XSETFASTINT (p->use_time, 0);
@@ -226,6 +231,7 @@ make_window ()
   p->vscroll = 0;
   XSETWINDOW (val, p);
   XSETFASTINT (p->last_point, 0);
+  p->frozen_window_start_p = 0;
   return val;
 }
 
@@ -244,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));
 }
 
@@ -269,9 +273,10 @@ POS defaults to point; WINDOW, to the selected window.")
      Lisp_Object pos, window;
 {
   register struct window *w;
-  struct text_pos top;
   register int posint;
   register struct buffer *buf;
+  struct text_pos top;
+  Lisp_Object in_window;
 
   if (NILP (pos))
     posint = PT;
@@ -282,39 +287,35 @@ POS defaults to point; WINDOW, to the selected window.")
     }
 
   w = decode_window (window);
+  buf = XBUFFER (w->buffer);
   SET_TEXT_POS_FROM_MARKER (top, w->start);
 
   /* If position above window, it's not visible.  */
   if (posint < CHARPOS (top))
-    return Qnil;
-
-  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))
-       return Qt;
-      return Qnil;
-    }
+    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
     {
       struct it it;
-
-      if (posint > BUF_ZV (buf))
-       return Qnil;
-
-      /* w->start can be out of range.  If it is, do something reasonable.  */
-      if (CHARPOS (top) < BUF_BEGV (buf)
-         || CHARPOS (top) > BUF_ZV (buf))
-       return Qnil;
-
       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);
-      return IT_CHARPOS (it) == posint ? Qt : Qnil;
+                 MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
+      in_window = IT_CHARPOS (it) == posint ? Qt : Qnil;
     }
+
+  return in_window;
 }
 \f
 static struct window *
@@ -375,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;
 }
@@ -426,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
@@ -436,6 +438,8 @@ and BOTTOM is one more than the bottommost row used by WINDOW\n\
    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,
+   return 5 or 6, and convert *X and *Y to window-relative corrdinates.
 
    X and Y are frame relative pixel coordinates.  */
 
@@ -446,7 +450,7 @@ coordinates_in_window (w, x, y)
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   int left_x, right_x, top_y, bottom_y;
-  int flags_area_width = FRAME_FLAGS_AREA_WIDTH (f);
+  int flags_area_width = FRAME_LEFT_FLAGS_AREA_WIDTH (f);
 
   if (w->pseudo_window_p)
     {
@@ -476,14 +480,20 @@ coordinates_in_window (w, x, y)
           && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
     /* On the mode line.  */
     return 2;
-  else if (WINDOW_WANTS_TOP_LINE_P (w)
-          && *y < top_y + CURRENT_TOP_LINE_HEIGHT (w))
+  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.  */
-    return 0;
+    {
+      /* 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))
@@ -509,7 +519,10 @@ 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, `top-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)
@@ -550,7 +563,13 @@ If they are on the border between WINDOW and its right sibling,\n\
       return Qvertical_line;
 
     case 4:
-      return Qtop_line;
+      return Qheader_line;
+
+    case 5:
+      return Qleft_bitmap_area;
+      
+    case 6:
+      return Qright_bitmap_area;
 
     default:
       abort ();
@@ -562,14 +581,14 @@ If they are on the border between WINDOW and its right sibling,\n\
    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.  TOOLBAR_P non-zero means detect toolbar windows.  */
+   unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.  */
 
 Lisp_Object
-window_from_coordinates (frame, x, y, part, toolbar_p)
+window_from_coordinates (frame, x, y, part, tool_bar_p)
      FRAME_PTR frame;
      int x, y;
      int *part;
-     int toolbar_p;
+     int tool_bar_p;
 {
   register Lisp_Object tem, first;
   int found;
@@ -590,14 +609,14 @@ window_from_coordinates (frame, x, y, part, toolbar_p)
     }
   while (!EQ (tem, first));
 
-  /* See if it's in the toolbar window, if a toolbar exists.  */
-  if (toolbar_p
-      && WINDOWP (frame->toolbar_window)
-      && XFASTINT (XWINDOW (frame->toolbar_window)->height)
-      && coordinates_in_window (XWINDOW (frame->toolbar_window), &x, &y))
+  /* 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->toolbar_window;
+      return frame->tool_bar_window;
     }
 
   return Qnil;
@@ -615,9 +634,8 @@ column 0.")
   struct frame *f;
 
   if (NILP (frame))
-    XSETFRAME (frame, selected_frame);
-  else
-    CHECK_LIVE_FRAME (frame, 2);
+    frame = selected_frame;
+  CHECK_LIVE_FRAME (frame, 2);
   f = XFRAME (frame);
 
   /* Check that arguments are integers or floats.  */
@@ -702,8 +720,21 @@ if it isn't already recorded.")
            && XFASTINT (w->last_modified) >= MODIFF))
     {
       int opoint = PT, opoint_byte = PT_BYTE;
-      TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
-                       XMARKER (w->start)->bytepos);
+
+      /* 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);
@@ -728,7 +759,7 @@ DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
     Fgoto_char (pos);
   else
     set_marker_restricted (w->pointm, pos, w->buffer);
-
+  
   return pos;
 }
 
@@ -752,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;
 }
 
@@ -905,6 +937,8 @@ replace_window (old, replacement)
   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))
@@ -1192,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));
 
@@ -1211,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
@@ -1344,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.  */
@@ -1455,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)
@@ -1475,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
@@ -1949,22 +1985,27 @@ window_fixed_size_p (w, width_p, check_siblings_p)
     }
   else if (BUFFERP (w->buffer))
     {
-      Lisp_Object val;
-      struct buffer *old = current_buffer;
-
-      current_buffer = XBUFFER (w->buffer);
-      val = find_symbol_value (Qfixed_window_size);
-      current_buffer = old;
-
-      fixed_p = 0;
-      if (!EQ (val, Qunbound))
+      if (w->height_fixed_p && !width_p)
+       fixed_p = 1;
+      else
        {
-         fixed_p = !NILP (val);
-         
-         if (fixed_p
-             && ((EQ (val, Qheight) && width_p)
-                 || (EQ (val, Qwidth) && !width_p)))
-           fixed_p = 0;
+         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;
+           }
        }
 
       /* Can't tell if this one is resizable without looking at
@@ -2068,7 +2109,7 @@ window_min_size_1 (w, width_p)
        {
          if (MINI_WINDOW_P (w)
              || (!WINDOW_WANTS_MODELINE_P (w)
-                 && !WINDOW_WANTS_TOP_LINE_P (w)))
+                 && !WINDOW_WANTS_HEADER_LINE_P (w)))
            size = 1;
          else
            size = window_min_height;
@@ -2081,17 +2122,22 @@ window_min_size_1 (w, width_p)
 
 /* 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.  Set *FIXED to 1 if W is
-   fixed-size unless FIXED is null.  */
+   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.  */
 
 static int
-window_min_size (w, width_p, fixed)
+window_min_size (w, width_p, ignore_fixed_p, fixed)
      struct window *w;
-     int width_p, *fixed;
+     int width_p, ignore_fixed_p, *fixed;
 {
   int size, fixed_p;
 
-  fixed_p = window_fixed_size_p (w, width_p, 1);
+  if (ignore_fixed_p)
+    fixed_p = 0;
+  else
+    fixed_p = window_fixed_size_p (w, width_p, 1);
+  
   if (fixed)
     *fixed = fixed_p;
   
@@ -2099,7 +2145,7 @@ window_min_size (w, width_p, fixed)
     size = width_p ? XFASTINT (w->width) : XFASTINT (w->height);
   else
     size = window_min_size_1 (w, width_p);
-
+      
   return size;
 }
 
@@ -2361,8 +2407,7 @@ set_window_buffer (window, buffer, run_hooks_p)
     }
 
   /* Set left and right marginal area width from buffer.  */
-  Fset_window_margins (b->left_margin_width, b->right_margin_width,
-                      window);
+  Fset_window_margins (window, b->left_margin_width, b->right_margin_width);
 
   if (run_hooks_p)
     {
@@ -2387,7 +2432,6 @@ BUFFER can be a buffer or buffer name.")
 {
   register Lisp_Object tem;
   register struct window *w = decode_window (window);
-  struct buffer *b;
 
   buffer = Fget_buffer (buffer);
   CHECK_BUFFER (buffer, 1);
@@ -2430,6 +2474,7 @@ select_window_1 (window, recordflag)
 {
   register struct window *w;
   register struct window *ow = XWINDOW (selected_window);
+  struct frame *sf;
 
   CHECK_LIVE_WINDOW (window, 0);
 
@@ -2448,7 +2493,8 @@ select_window_1 (window, recordflag)
                     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
@@ -2458,7 +2504,7 @@ select_window_1 (window, recordflag)
       Fselect_frame (WINDOW_FRAME (w), Qnil);
     }
   else
-    selected_frame->selected_window = window;
+    sf->selected_window = window;
 
   if (recordflag)
     record_buffer (w->buffer);
@@ -2499,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;
 }
 
@@ -2604,6 +2654,7 @@ If FRAME is nil, search only the selected frame\n\
      register Lisp_Object buffer, not_this_window, frame;
 {
   register Lisp_Object window, tem, swp;
+  struct frame *f;
 
   swp = Qnil;
   buffer = Fget_buffer (buffer);
@@ -2663,17 +2714,17 @@ If FRAME is nil, search only the selected frame\n\
       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)
@@ -2685,8 +2736,7 @@ If FRAME is nil, search only the selected frame\n\
 
       /* 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);
@@ -2754,14 +2804,9 @@ If FRAME is nil, search only the selected frame\n\
            {
              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);
            }
        }
     }
@@ -2787,7 +2832,7 @@ 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))
@@ -2796,7 +2841,7 @@ temp_output_buffer_show (buf)
     {
       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);
@@ -2995,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);
@@ -3010,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);
@@ -3047,11 +3092,12 @@ window_width (window)
    fullfil the size request.  If they become too small in the process,
    they will be deleted.  */
 
-void
-change_window_height (delta, widthflag)
+static void
+enlarge_window (window, delta, widthflag)
+     Lisp_Object window;
      int delta, widthflag;
 {
-  Lisp_Object parent, window, next, prev;
+  Lisp_Object parent, next, prev;
   struct window *p;
   int *sizep, maximum;
   int (*sizefun) P_ ((Lisp_Object))
@@ -3064,7 +3110,6 @@ change_window_height (delta, widthflag)
   check_min_window_sizes ();
 
   /* Give up if this window cannot be resized.  */
-  window = selected_window;
   if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
     error ("Window is not resizable");
 
@@ -3097,10 +3142,10 @@ change_window_height (delta, widthflag)
     maxdelta = (!NILP (parent) ? (*sizefun) (parent) - *sizep
                : !NILP (p->next) ? ((*sizefun) (p->next)
                                     - window_min_size (XWINDOW (p->next),
-                                                       widthflag, 0))
+                                                       widthflag, 0, 0))
                : !NILP (p->prev) ? ((*sizefun) (p->prev)
                                     - window_min_size (XWINDOW (p->prev),
-                                                       widthflag, 0))
+                                                       widthflag, 0, 0))
                /* This is a frame with only one window, a minibuffer-only
                   or a minibufferless frame.  */
                : (delta = 0));
@@ -3112,7 +3157,7 @@ change_window_height (delta, widthflag)
       delta = maxdelta;
   }
 
-  if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0))
+  if (*sizep + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
     {
       delete_window (window);
       return;
@@ -3125,10 +3170,10 @@ change_window_height (delta, widthflag)
   maximum = 0;
   for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
     maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
-                                                   widthflag, 0);
+                                                   widthflag, 0, 0);
   for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
     maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
-                                                   widthflag, 0);
+                                                   widthflag, 0, 0);
 
   /* If we can get it all from them, do so.  */
   if (delta <= maximum)
@@ -3149,7 +3194,7 @@ change_window_height (delta, widthflag)
            {
              int this_one = ((*sizefun) (next)
                              - window_min_size (XWINDOW (next),
-                                                widthflag, &fixed_p));
+                                                widthflag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -3171,7 +3216,7 @@ change_window_height (delta, widthflag)
            {
              int this_one = ((*sizefun) (prev)
                              - window_min_size (XWINDOW (prev),
-                                                widthflag, &fixed_p));
+                                                widthflag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -3282,6 +3327,239 @@ change_window_height (delta, widthflag)
 #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
@@ -3347,7 +3625,7 @@ window_internal_width (w)
   /* On window-systems, areas to the left and right of the window
      are used to display bitmaps there.  */
   if (FRAME_WINDOW_P (f))
-    width -= 2 * FRAME_FLAGS_AREA_COLS (f);
+    width -= FRAME_FLAGS_AREA_COLS (f);
 
   return width;
 }
@@ -3876,6 +4154,7 @@ redraws with point in the center of the current window.")
     {
       extern int frame_garbaged;
 
+      Fredraw_frame (w->frame);
       SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
       XSETFASTINT (arg, ht / 2);
     }
@@ -3954,7 +4233,7 @@ 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_toolbar_lines;
+    Lisp_Object frame_tool_bar_lines;
     Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object current_buffer;
@@ -4069,7 +4348,7 @@ the return value is nil.  Otherwise the value is t.")
       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_toolbar_lines = FRAME_TOOLBAR_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.  */
@@ -4078,15 +4357,15 @@ the return value is nil.  Otherwise the value is t.")
       if (XFASTINT (data->frame_height) != previous_frame_height
          || XFASTINT (data->frame_width) != previous_frame_width)
        change_frame_size (f, XFASTINT (data->frame_height),
-                          XFASTINT (data->frame_width), 0, 0);
+                          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, make_number (0));
 #ifdef HAVE_WINDOW_SYSTEM
-      if (XFASTINT (data->frame_toolbar_lines)
-         != previous_frame_toolbar_lines)
-       x_set_toolbar_lines (f, data->frame_toolbar_lines, make_number (0));
+      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
 
@@ -4245,15 +4524,15 @@ the return value is nil.  Otherwise the value is t.")
       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, make_number (previous_frame_menu_bar_lines),
                              make_number (0));
 #ifdef HAVE_WINDOW_SYSTEM
-      if (previous_frame_toolbar_lines != FRAME_TOOLBAR_LINES (f))
-       x_set_toolbar_lines (f, make_number (previous_frame_toolbar_lines),
-                            make_number (0));
+      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
 
@@ -4490,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));
@@ -4507,8 +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));
-  XSETFASTINT (data->frame_toolbar_lines, FRAME_TOOLBAR_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;
@@ -4560,27 +4836,26 @@ 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.")
-  (left, right, window)
+  (window, left, right)
      Lisp_Object window, left, right;
 {
   struct window *w = decode_window (window);
-  struct frame *f = XFRAME (w->frame);
 
   if (!NILP (left))
-    CHECK_NUMBER_OR_FLOAT (left, 0);
+    CHECK_NUMBER_OR_FLOAT (left, 1);
   if (!NILP (right))
-    CHECK_NUMBER_OR_FLOAT (right, 0);
+    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 (left)->data <= 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 (right)->data <= 0))
+      || (FLOATP (right) && XFLOAT_DATA (right) <= 0))
     XSETFASTINT (right, 0);
   if (INTEGERP (right) && XFASTINT (right) == 0)
     right = Qnil;
@@ -4621,43 +4896,51 @@ 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))
-    return CANON_Y_FROM_PIXEL_Y (f, w->vscroll);
+    result = CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
   else
-    return make_number (0);
+    result = make_number (0);
+  return result;
 }
 
 
 DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
-       1, 2, 0,
-  "Set amount by WINDOW should be scrolled vertically to VSCROLL.\n\
+       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\
-multiple of the canonical character height of WINDOW.")
-  (vscroll, window)
-     Lisp_Object vscroll, window;
+non-negative multiple of the canonical character height of WINDOW.")
+  (window, vscroll)
+     Lisp_Object window, vscroll;
 {
   struct window *w;
   struct frame *f;
   
-  CHECK_NUMBER_OR_FLOAT (vscroll, 0);
-  
   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 = min (0, CANON_Y_UNIT (f) * XFLOATINT (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.  */
@@ -4665,12 +4948,81 @@ multiple of the canonical character height of WINDOW.")
        adjust_glyphs (f);
       
       /* Prevent redisplay shortcuts.  */
-      XBUFFER (w->buffer)->clip_changed = 1;
+      XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
     }
   
-  return Qnil;
+  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
 /***********************************************************************
@@ -4792,11 +5144,12 @@ and scrolling positions.")
 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;
 }
@@ -4804,8 +5157,13 @@ init_window_once ()
 void
 syms_of_window ()
 {
-  Qfixed_window_size = intern ("fixed-window-size");
-  staticpro (&Qfixed_window_size);
+  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