(read_char): Save and restore echo_string when
[bpt/emacs.git] / src / window.c
index bac6c5a..6fe547b 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, 2002, 2003
+   Copyright (C) 1985,86,87, 1993,94,95,96,97,98, 2000,01,02,03,04
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -204,7 +204,7 @@ static int window_initialized;
 Lisp_Object Qwindow_configuration_change_hook;
 Lisp_Object Vwindow_configuration_change_hook;
 
-/* Nonzero means scroll commands try to put point
+/* Non-nil means scroll commands try to put point
    at the same screen height as previously.  */
 
 Lisp_Object Vscroll_preserve_screen_position;
@@ -241,7 +241,8 @@ make_window ()
   register struct window *p;
 
   p = allocate_window ();
-  XSETFASTINT (p->sequence_number, ++sequence_number);
+  ++sequence_number;
+  XSETFASTINT (p->sequence_number, sequence_number);
   XSETFASTINT (p->left_col, 0);
   XSETFASTINT (p->top_line, 0);
   XSETFASTINT (p->total_lines, 0);
@@ -260,6 +261,7 @@ make_window ()
   bzero (&p->last_cursor, sizeof (p->last_cursor));
   bzero (&p->phys_cursor, sizeof (p->phys_cursor));
   p->desired_matrix = p->current_matrix = 0;
+  p->nrows_scale_factor = p->ncols_scale_factor = 1;
   p->phys_cursor_type = -1;
   p->phys_cursor_width = -1;
   p->must_be_updated_p = 0;
@@ -318,11 +320,17 @@ WINDOW defaults to the selected window.  */)
 
 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
        Spos_visible_in_window_p, 0, 3, 0,
-       doc: /* Return t if position POS is currently on the frame in WINDOW.
+       doc: /* Return non-nil if position POS is currently on the frame in WINDOW.
 Return nil if that position is scrolled vertically out of view.
 If a character is only partially visible, nil is returned, unless the
 optional argument PARTIALLY is non-nil.
-POS defaults to point in WINDOW; WINDOW defaults to the selected window.  */)
+If POS is only out of view because of horizontal scrolling, return non-nil.
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.
+
+If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
+return value is a list (X Y FULLY) where X and Y are the pixel coordinates
+relative to the top left corner of the window, and FULLY is t if the
+character after POS is fully visible and nil otherwise.  */)
      (pos, window, partially)
      Lisp_Object pos, window, partially;
 {
@@ -330,8 +338,9 @@ POS defaults to point in WINDOW; WINDOW defaults to the selected window.  */)
   register int posint;
   register struct buffer *buf;
   struct text_pos top;
-  Lisp_Object in_window;
-  int fully_p;
+  Lisp_Object in_window = Qnil;
+  int fully_p = 1;
+  int x, y;
 
   w = decode_window (window);
   buf = XBUFFER (w->buffer);
@@ -347,38 +356,20 @@ POS defaults to point in WINDOW; WINDOW defaults to the selected window.  */)
   else
     posint = XMARKER (w->pointm)->charpos;
 
-  /* If position is above window start, it's not visible.  */
-  if (posint < CHARPOS (top))
-    in_window = Qnil;
-  else if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)
-          && XFASTINT (w->last_overlay_modified) >= BUF_OVERLAY_MODIFF (buf)
-          && posint < BUF_Z (buf) - XFASTINT (w->window_end_pos))
-    {
-      /* If frame is up-to-date, and POSINT is < window end pos, use
-        that info.  This doesn't work for POSINT == end pos, because
-        the window end pos is actually the position _after_ the last
-        char in the window.  */
-      if (NILP (partially))
-       {
-         pos_visible_p (w, posint, &fully_p, NILP (partially));
-         in_window = fully_p ? Qt : Qnil;
-       }
-      else
-       in_window = Qt;
-    }
-  else if (posint > BUF_ZV (buf))
-    in_window = Qnil;
-  else if (CHARPOS (top) < BUF_BEGV (buf) || CHARPOS (top) > BUF_ZV (buf))
-    /* If window start is out of range, do something reasonable.  */
-    in_window = Qnil;
-  else
-    {
-      if (pos_visible_p (w, posint, &fully_p, NILP (partially)))
-       in_window = !NILP (partially) || fully_p ? Qt : Qnil;
-      else
-       in_window = Qnil;
-    }
-
+  /* If position is above window start or outside buffer boundaries,
+     or if window start is out of range, position is not visible.  */
+  if (posint >= CHARPOS (top)
+      && posint <= BUF_ZV (buf)
+      && CHARPOS (top) >= BUF_BEGV (buf)
+      && CHARPOS (top) <= BUF_ZV (buf)
+      && pos_visible_p (w, posint, &fully_p, &x, &y, NILP (partially))
+      && (!NILP (partially) || fully_p))
+    in_window = Qt;
+
+  if (!NILP (in_window) && !NILP (partially))
+    in_window = Fcons (make_number (x),
+                      Fcons (make_number (y),
+                             Fcons (fully_p ? Qt : Qnil, Qnil)));
   return in_window;
 }
 
@@ -406,7 +397,8 @@ decode_any_window (window)
 }
 
 DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
-       doc: /* Return the buffer that WINDOW is displaying.  */)
+       doc: /* Return the buffer that WINDOW is displaying.
+WINDOW defaults to the selected window.  */)
      (window)
      Lisp_Object window;
 {
@@ -442,7 +434,7 @@ 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.
+Return NCOL.  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.  */)
@@ -556,7 +548,7 @@ display margins, fringes, header line, and/or mode line.  */)
 }
 
 DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge coordinates of WINDOW.
+       doc: /* Return a list of the edge pixel coordinates of WINDOW.
 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
 RIGHT is one more than the rightmost x position used by text in WINDOW,
 and BOTTOM is one more than the bottommost y position used by text in WINDOW.
@@ -588,6 +580,8 @@ display margins, fringes, header line, and/or mode line.  */)
    if it is on the window's modeline, return ON_MODE_LINE;
    if it is on the border between the window and its right sibling,
       return ON_VERTICAL_BORDER.
+   if it is on a scroll bar,
+      return ON_SCROLL_BAR.
    if it is on the window's top line, return ON_HEADER_LINE;
    if it is in left or right fringe of the window,
       return ON_LEFT_FRINGE or ON_RIGHT_FRINGE, and convert *X and *Y
@@ -614,9 +608,6 @@ coordinates_in_window (w, x, y)
   int grabbable_width = ux;
   int lmargin_width, rmargin_width, text_left, text_right;
 
-  if (*x < x0 || *x >= x1)
-    return ON_NOTHING;
-
   /* In what's below, we subtract 1 when computing right_x because we
      want the rightmost pixel, which is given by left_pixel+width-1.  */
   if (w->pseudo_window_p)
@@ -666,6 +657,9 @@ coordinates_in_window (w, x, y)
            return ON_VERTICAL_BORDER;
        }
 
+      if (*x < x0 || *x >= x1)
+       return ON_NOTHING;
+
       /* Convert X and Y to window relative coordinates.
         Mode line starts at left edge of window.  */
       *x -= x0;
@@ -680,9 +674,12 @@ coordinates_in_window (w, x, y)
       goto header_vertical_border_check;
     }
 
+  if (*x < x0 || *x >= x1)
+    return ON_NOTHING;
+
   /* Outside any interesting column?  */
   if (*x < left_x || *x > right_x)
-    return ON_NOTHING;
+    return ON_SCROLL_BAR;
 
   lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
   rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
@@ -792,8 +789,8 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
   ly = Fcdr (coordinates);
   CHECK_NUMBER_OR_FLOAT (lx);
   CHECK_NUMBER_OR_FLOAT (ly);
-  x = FRAME_PIXEL_X_FROM_CANON_X (f, lx);
-  y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly);
+  x = FRAME_PIXEL_X_FROM_CANON_X (f, lx) + FRAME_INTERNAL_BORDER_WIDTH (f);
+  y = FRAME_PIXEL_Y_FROM_CANON_Y (f, ly) + FRAME_INTERNAL_BORDER_WIDTH (f);
 
   switch (coordinates_in_window (w, &x, &y))
     {
@@ -827,6 +824,10 @@ If they are in the windows's left or right marginal areas, `left-margin'\n\
     case ON_RIGHT_MARGIN:
       return Qright_margin;
 
+    case ON_SCROLL_BAR:
+      /* Historically we are supposed to return nil in this case.  */
+      return Qnil;
+
     default:
       abort ();
     }
@@ -947,8 +948,10 @@ column 0.  */)
   CHECK_NUMBER_OR_FLOAT (y);
 
   return window_from_coordinates (f,
-                                 FRAME_PIXEL_X_FROM_CANON_X (f, x),
-                                 FRAME_PIXEL_Y_FROM_CANON_Y (f, y),
+                                 (FRAME_PIXEL_X_FROM_CANON_X (f, x)
+                                  + FRAME_INTERNAL_BORDER_WIDTH (f)),
+                                 (FRAME_PIXEL_Y_FROM_CANON_Y (f, y)
+                                  + FRAME_INTERNAL_BORDER_WIDTH (f)),
                                  0, 0, 0, 0);
 }
 
@@ -998,6 +1001,8 @@ DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
 This is updated by redisplay, when it runs to completion.
 Simply changing the buffer text or setting `window-start'
 does not update this value.
+Return nil if there is no recorded value.  \(This can happen if the
+last redisplay of WINDOW was preempted, and did not finish.)
 If UPDATE is non-nil, compute the up-to-date position
 if it isn't already recorded.  */)
      (window, update)
@@ -1063,7 +1068,8 @@ if it isn't already recorded.  */)
 }
 
 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
-       doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.  */)
+       doc: /* Make point value in WINDOW be at position POS in WINDOW's buffer.
+Return POS.  */)
      (window, pos)
      Lisp_Object window, pos;
 {
@@ -1086,6 +1092,7 @@ DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
 
 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
        doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
+Return POS.
 Optional third arg NOFORCE non-nil inhibits next redisplay
 from overriding motion of point in order to display at this exact start.  */)
      (window, pos, noforce)
@@ -1604,7 +1611,7 @@ decode_next_window_args (window, minibuf, all_frames)
                   : Qnil);
   else if (EQ (*all_frames, Qvisible))
     ;
-  else if (XFASTINT (*all_frames) == 0)
+  else if (EQ (*all_frames, make_number (0)))
     ;
   else if (FRAMEP (*all_frames))
     ;
@@ -1760,8 +1767,8 @@ DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
        doc: /* Select the ARG'th different window on this frame.
 All windows on current frame are arranged in a cyclic order.
 This command selects the window ARG steps away in that order.
-A negative ARG moves in the opposite order.  If the optional second
-argument ALL_FRAMES is non-nil, cycle through all frames.  */)
+A negative ARG moves in the opposite order.  The optional second
+argument ALL_FRAMES has the same meaning as in `next-window', which see.  */)
      (arg, all_frames)
      Lisp_Object arg, all_frames;
 {
@@ -1811,7 +1818,7 @@ static Lisp_Object
 window_list_1 (window, minibuf, all_frames)
      Lisp_Object window, minibuf, all_frames;
 {
-  Lisp_Object tail, list;
+  Lisp_Object tail, list, rest;
 
   decode_next_window_args (&window, &minibuf, &all_frames);
   list = Qnil;
@@ -1820,7 +1827,17 @@ window_list_1 (window, minibuf, all_frames)
     if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
       list = Fcons (XCAR (tail), list);
 
-  return Fnreverse (list);
+  /* Rotate the list to start with WINDOW.  */
+  list = Fnreverse (list);
+  rest = Fmemq (window, list);
+  if (!NILP (rest) && !EQ (rest, list))
+    {
+      for (tail = list; !EQ (XCDR (tail), rest); tail = XCDR (tail))
+       ;
+      XSETCDR (tail, Qnil);
+      list = nconc2 (rest, list);
+    }
+  return list;
 }
 
 
@@ -1868,7 +1885,7 @@ window_loop (type, obj, mini, frames)
 
   if (f)
     frame_arg = Qlambda;
-  else if (XFASTINT (frames) == 0)
+  else if (EQ (frames, make_number (0)))
     frame_arg = frames;
   else if (EQ (frames, Qvisible))
     frame_arg = frames;
@@ -2078,6 +2095,10 @@ check_all_windows ()
 
 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
        doc: /* Return the window least recently selected or used for display.
+Return a full-width window if possible.
+A minibuffer window is never a candidate.
+A dedicated window is never a candidate, so if all windows are dedicated,
+the value is nil.
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
 If FRAME is t, search all frames.
@@ -2097,6 +2118,9 @@ If FRAME is a frame, search only that frame.  */)
 
 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
        doc: /* Return the largest window in area.
+A minibuffer window is never a candidate.
+A dedicated window is never a candidate, so if all windows are dedicated,
+the value is nil.
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
 If FRAME is t, search all frames.
@@ -2111,6 +2135,7 @@ If FRAME is a frame, search only that frame.  */)
 
 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0,
        doc: /* Return a window currently displaying BUFFER, or nil if none.
+BUFFER can be a buffer or a buffer name.
 If optional argument FRAME is `visible', search all visible frames.
 If optional argument FRAME is 0, search all visible and iconified frames.
 If FRAME is t, search all frames.
@@ -2193,6 +2218,7 @@ value is reasonable when this function is called.  */)
 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
        1, 2, "bDelete windows on (buffer): ",
        doc: /* Delete all windows showing BUFFER.
+BUFFER must be a buffer or the name of an existing buffer.
 Optional second argument FRAME controls which frames are affected.
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
@@ -2222,7 +2248,8 @@ If FRAME is a frame, search only that frame.  */)
 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
        Sreplace_buffer_in_windows,
        1, 1, "bReplace buffer in windows: ",
-       doc: /* Replace BUFFER with some other buffer in all windows showing it.  */)
+       doc: /* Replace BUFFER with some other buffer in all windows showing it.
+BUFFER may be a buffer or the name of an existing buffer.  */)
      (buffer)
      Lisp_Object buffer;
 {
@@ -2635,6 +2662,9 @@ shrink_windows (total, size, nchildren, shrinkable,
             --shrinkable;
             total_removed += smallest;
 
+            /* We don't know what the smallest is now.  */
+            smallest = total;
+
             /* Out of for, just remove one window at the time and
                check again if we have enough space.  */
             break;
@@ -2659,6 +2689,16 @@ shrink_windows (total, size, nchildren, shrinkable,
      that are left and still can be shrunk.  */
   while (total_shrink > total_removed)
     {
+      int nonzero_sizes = 0;
+      int nonzero_idx = -1;
+
+      for (i = 0; i < nchildren; ++i)
+        if (new_sizes[i] > 0)
+          {
+            ++nonzero_sizes;
+            nonzero_idx = i;
+          }
+
       for (i = 0; i < nchildren; ++i)
         if (new_sizes[i] > min_size)
           {
@@ -2669,6 +2709,25 @@ shrink_windows (total, size, nchildren, shrinkable,
                check again if we have enough space.  */
             break;
           }
+
+
+      /* Special case, only one window left.  */
+      if (nonzero_sizes == 1)
+        break;
+    }
+
+  /* Any surplus due to rounding, we add to windows that are left.  */
+  while (total_shrink < total_removed)
+    {
+      for (i = 0; i < nchildren; ++i)
+        {
+          if (new_sizes[i] != 0 && total_shrink < total_removed)
+            {
+              ++new_sizes[i];
+              --total_removed;
+              break;
+            }
+        }
     }
 
   return new_sizes;
@@ -2957,6 +3016,9 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
   if (EQ (window, selected_window))
     b->last_selected_window = window;
 
+  /* Let redisplay errors through.  */
+  b->display_error_modiff = 0;
+
   /* Update time stamps of buffer display.  */
   if (INTEGERP (b->display_count))
     XSETINT (b->display_count, XINT (b->display_count) + 1);
@@ -3034,11 +3096,13 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
 
 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
        doc: /* Make WINDOW display BUFFER as its contents.
-BUFFER can be a buffer or buffer name.
-Optional third arg KEEP_MARGINS non-nil means that WINDOW's current
+BUFFER can be a buffer or the name of an existing buffer.
+Optional third arg KEEP-MARGINS non-nil means that WINDOW's current
 display margins, fringe widths, and scroll bar settings are maintained;
 the default is to reset these from BUFFER's local settings or the frame
-defaults.  */)
+defaults.
+
+This function runs the hook `window-scroll-functions'.  */)
      (window, buffer, keep_margins)
      register Lisp_Object window, buffer, keep_margins;
 {
@@ -3074,8 +3138,8 @@ defaults.  */)
 
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 2, 0,
        doc: /* Select WINDOW.  Most editing will apply to WINDOW's buffer.
-If WINDOW is not already selected, also make WINDOW's buffer current.
-Also make WINDOW the frame's selected window.
+If WINDOW is not already selected, make WINDOW's buffer current
+and make WINDOW the frame's selected window.  Return WINDOW.
 Optional second arg NORECORD non-nil means
 do not put this buffer at the front of the list of recently selected ones.
 
@@ -3093,7 +3157,8 @@ selects the buffer of the selected window before each command.  */)
   w = XWINDOW (window);
   w->frozen_window_start_p = 0;
 
-  XSETFASTINT (w->use_time, ++window_select_count);
+  ++window_select_count;
+  XSETFASTINT (w->use_time, window_select_count);
   if (EQ (window, selected_window))
     return window;
 
@@ -3190,10 +3255,13 @@ display_buffer_1 (window)
 }
 
 DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
-       doc: /* Returns non-nil if a buffer named BUFFER-NAME would be created specially.
-The value is actually t if the frame should be called with default frame
-parameters, and a list of frame parameters if they were specified.
-See `special-display-buffer-names', and `special-display-regexps'.  */)
+       doc: /* Returns non-nil if a buffer named BUFFER-NAME gets a special frame.
+If the value is t, a frame would be created for that buffer
+using the default frame parameters.  If the value is a list,
+it is a list of frame parameters that would be used
+to make a frame for that buffer.
+The variables `special-display-buffer-names'
+and `special-display-regexps' control this.  */)
      (buffer_name)
      Lisp_Object buffer_name;
 {
@@ -3259,7 +3327,8 @@ See `same-window-buffer-names' and `same-window-regexps'.  */)
 DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
        "BDisplay buffer: \nP",
        doc: /* Make BUFFER appear in some window but don't select it.
-BUFFER can be a buffer or a buffer name.
+BUFFER must  be the name of an existing buffer, or, when called from Lisp,
+a buffer.
 If BUFFER is shown already in some window, just use that one,
 unless the window is the selected window and the optional second
 argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).
@@ -3268,9 +3337,10 @@ Returns the window displaying BUFFER.
 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',
-`same-window-buffer-names', and `same-window-regexps' customize how certain
-buffer names are handled.
+The variables `special-display-buffer-names',
+`special-display-regexps', `same-window-buffer-names', and
+`same-window-regexps' customize how certain buffer names are handled.
+The latter two take effect only if NOT-THIS-WINDOW is t.
 
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
@@ -3281,6 +3351,10 @@ If FRAME is nil, search only the selected frame
  unless `pop-up-frames' or `display-buffer-reuse-frames' is non-nil,
  which means search visible and iconified frames.
 
+If a full-width window on a splittable frame is available to display
+the buffer, it may be split, subject to the value of the variable
+`split-height-threshold'.
+
 If `even-window-heights' is non-nil, window heights will be evened out
 if displaying the buffer causes two vertically adjacent windows to be
 displayed.  */)
@@ -3458,7 +3532,7 @@ DEFUN ("force-window-update", Fforce_window_update, Sforce_window_update,
        0, 1, 0,
        doc: /* Force redisplay of all windows.
 If optional arg OBJECT is a window, force redisplay of that window only.
-If OBJECT is a buffer or buffer name, force redisplay of all windows 
+If OBJECT is a buffer or buffer name, force redisplay of all windows
 displaying that buffer.  */)
      (object)
      Lisp_Object object;
@@ -3480,7 +3554,7 @@ displaying that buffer.  */)
       ++update_mode_lines;
       return Qt;
     }
-    
+
   if (STRINGP (object))
     object = Fget_buffer (object);
   if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
@@ -3545,7 +3619,7 @@ temp_output_buffer_show (buf)
          Lisp_Object prev_window, prev_buffer;
          prev_window = selected_window;
          XSETBUFFER (prev_buffer, old);
-         
+
          /* Select the window that was chosen, for running the hook.
             Note: Both Fselect_window and select_window_norecord may
             set-buffer to the buffer displayed in the window,
@@ -3575,7 +3649,8 @@ make_dummy_parent (window)
       = ((struct Lisp_Vector *)o)->contents[i];
   XSETWINDOW (new, p);
 
-  XSETFASTINT (p->sequence_number, ++sequence_number);
+  ++sequence_number;
+  XSETFASTINT (p->sequence_number, sequence_number);
 
   /* Put new into window structure in place of window */
   replace_window (window, new);
@@ -3596,7 +3671,12 @@ DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
 WINDOW defaults to selected one and SIZE to half its size.
 If optional third arg HORFLAG is non-nil, split side by side
 and put SIZE columns in the first of the pair.  In that case,
-SIZE includes that window's scroll bar, or the divider column to its right.  */)
+SIZE includes that window's scroll bar, or the divider column to its right.
+Interactively, all arguments are nil.
+
+Returns the newly created window (which is the lower or rightmost one).
+The upper or leftmost window is the original one and remains selected.
+See Info node `(elisp)Splitting Windows' for more details and examples.*/)
      (window, size, horflag)
      Lisp_Object window, size, horflag;
 {
@@ -4468,7 +4548,7 @@ window_scroll_pixel_based (window, n, whole, noerror)
         results for variable height lines.  */
       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
       it.current_y = it.last_visible_y;
-      move_it_vertically (&it, - window_box_height (w) / 2);
+      move_it_vertically_backward (&it, window_box_height (w) / 2);
 
       /* The function move_iterator_vertically may move over more than
         the specified y-distance.  If it->w is small, e.g. a
@@ -4478,14 +4558,14 @@ window_scroll_pixel_based (window, n, whole, noerror)
       if (it.current_y <= 0)
        {
          init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
-         move_it_vertically (&it, 0);
+         move_it_vertically_backward (&it, 0);
          it.current_y = 0;
        }
 
       start = it.current.pos;
     }
 
-  /* If scroll_preserve_screen_position is non-zero, we try to set
+  /* If scroll_preserve_screen_position is non-nil, we try to set
      point in the same window line as it is now, so get that line.  */
   if (!NILP (Vscroll_preserve_screen_position))
     {
@@ -4587,17 +4667,25 @@ window_scroll_pixel_based (window, n, whole, noerror)
       w->force_start = Qt;
     }
 
+  /* The rest of this function uses current_y in a nonstandard way,
+     not including the height of the header line if any.  */
   it.current_y = it.vpos = 0;
 
-  /* Preserve the screen position if we must.  */
+  /* Preserve the screen position if we should.  */
   if (preserve_y >= 0)
     {
+      /* If we have a header line, take account of it.  */
+      if (WINDOW_WANTS_HEADER_LINE_P (w))
+       preserve_y -= CURRENT_HEADER_LINE_HEIGHT (w);
+
       move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
     }
   else
     {
-      /* Move PT out of scroll margins.  */
+      /* Move PT out of scroll margins.
+        This code wants current_y to be zero at the window start position
+        even if there is a header line.  */
       this_scroll_margin = max (0, scroll_margin);
       this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) / 4);
       this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
@@ -4677,7 +4765,7 @@ window_scroll_line_based (window, n, whole, noerror)
 
   posit = *compute_motion (startpos, 0, 0, 0,
                           PT, ht, 0,
-                          window_box_text_cols (w), XINT (w->hscroll),
+                          -1, XINT (w->hscroll),
                           0, w);
   original_vpos = posit.vpos;
 
@@ -4833,7 +4921,8 @@ scroll_command (n, direction)
 }
 
 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
-       doc: /* Scroll text of current window upward ARG lines; or near full screen if no ARG.
+       doc: /* Scroll text of current window upward ARG lines.
+If ARG is omitted or nil, scroll upward by a near full screen.
 A near full screen is `next-screen-context-lines' less than a full screen.
 Negative ARG means scroll downward.
 If ARG is the atom `-', scroll downward by nearly full screen.
@@ -4846,7 +4935,8 @@ When calling from a program, supply as argument a number, nil, or `-'.  */)
 }
 
 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
-       doc: /* Scroll text of current window down ARG lines; or near full screen if no ARG.
+       doc: /* Scroll text of current window down ARG lines.
+If ARG is omitted or nil, scroll down by a near full screen.
 A near full screen is `next-screen-context-lines' less than a full screen.
 Negative ARG means scroll upward.
 If ARG is the atom `-', scroll upward by nearly full screen.
@@ -4860,10 +4950,11 @@ When calling from a program, supply as argument a number, nil, or `-'.  */)
 \f
 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0,
        doc: /* Return the other window for \"other window scroll\" commands.
-If in the minibuffer, `minibuffer-scroll-window' if non-nil
-specifies the window.
 If `other-window-scroll-buffer' is non-nil, a window
-showing that buffer is used.  */)
+showing that buffer is used.
+If in the minibuffer, `minibuffer-scroll-window' if non-nil
+specifies the window.  This takes precedence over
+`other-window-scroll-buffer'.  */)
      ()
 {
   Lisp_Object window;
@@ -4909,10 +5000,11 @@ if the current one is at the bottom.  Negative ARG means scroll downward.
 If ARG is the atom `-', scroll downward by nearly full screen.
 When calling from a program, supply as argument a number, nil, or `-'.
 
-If in the minibuffer, `minibuffer-scroll-window' if non-nil
-specifies the window to scroll.
 If `other-window-scroll-buffer' is non-nil, scroll the window
-showing that buffer, popping the buffer up if necessary.  */)
+showing that buffer, popping the buffer up if necessary.
+If in the minibuffer, `minibuffer-scroll-window' if non-nil
+specifies the window to scroll.  This takes precedence over
+`other-window-scroll-buffer'.  */)
      (arg)
      Lisp_Object arg;
 {
@@ -4948,17 +5040,17 @@ showing that buffer, popping the buffer up if necessary.  */)
   return Qnil;
 }
 \f
-DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "P",
+DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 2, "P\np",
        doc: /* Scroll selected window display ARG columns left.
 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
-lower bound for automatic scrolling, i.e. automatic scrolling
+If SET_MINIMUM is non-nil, the new scroll amount becomes the
+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;
+by this function.  This happens in an interactive call.  */)
+     (arg, set_minimum)
+     register Lisp_Object arg, set_minimum;
 {
   Lisp_Object result;
   int hscroll;
@@ -4972,23 +5064,23 @@ by this function.  */)
   hscroll = XINT (w->hscroll) + XINT (arg);
   result = Fset_window_hscroll (selected_window, make_number (hscroll));
 
-  if (interactive_p (0))
+  if (!NILP (set_minimum))
     w->min_hscroll = w->hscroll;
 
   return result;
 }
 
-DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "P",
+DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 2, "P\np",
        doc: /* Scroll selected window display ARG columns right.
 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
-lower bound for automatic scrolling, i.e. automatic scrolling
+If SET_MINIMUM is non-nil, the new scroll amount becomes the
+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;
+by this function.  This happens in an interactive call.  */)
+     (arg, set_minimum)
+     register Lisp_Object arg, set_minimum;
 {
   Lisp_Object result;
   int hscroll;
@@ -5002,7 +5094,7 @@ by this function.  */)
   hscroll = XINT (w->hscroll) - XINT (arg);
   result = Fset_window_hscroll (selected_window, make_number (hscroll));
 
-  if (interactive_p (0))
+  if (!NILP (set_minimum))
     w->min_hscroll = w->hscroll;
 
   return result;
@@ -5135,7 +5227,7 @@ and redisplay normally--don't erase and redraw the frame.  */)
 
          SET_TEXT_POS (pt, PT, PT_BYTE);
          start_display (&it, w, pt);
-         move_it_vertically (&it, - window_box_height (w) / 2);
+         move_it_vertically_backward (&it, window_box_height (w) / 2);
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
        }
@@ -5143,29 +5235,62 @@ and redisplay normally--don't erase and redraw the frame.  */)
        {
          struct it it;
          struct text_pos pt;
-         int y0, y1, h, nlines;
+         int nlines = - XINT (arg);
+         int extra_line_spacing;
+         int h = window_box_height (w);
 
          SET_TEXT_POS (pt, PT, PT_BYTE);
          start_display (&it, w, pt);
-         y0 = it.current_y;
+
+         /* Be sure we have the exact height of the full line containing PT.  */
+         move_it_by_lines (&it, 0, 1);
 
          /* The amount of pixels we have to move back is the window
             height minus what's displayed in the line containing PT,
             and the lines below.  */
-         nlines = - XINT (arg) - 1;
+         it.current_y = 0;
+         it.vpos = 0;
          move_it_by_lines (&it, nlines, 1);
 
-         y1 = line_bottom_y (&it);
+         if (it.vpos == nlines)
+           h -= it.current_y;
+         else
+           {
+             /* Last line has no newline */
+             h -= line_bottom_y (&it);
+             it.vpos++;
+           }
+
+         /* Don't reserve space for extra line spacing of last line.  */
+         extra_line_spacing = it.max_extra_line_spacing;
 
          /* 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) * FRAME_LINE_HEIGHT (it.f);
-
-         h = window_box_height (w) - (y1 - y0);
+           {
+             nlines -= it.vpos;
+             extra_line_spacing = it.extra_line_spacing;
+             h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
+           }
+         if (h <= 0)
+           return Qnil;
 
+         /* Now find the new top line (starting position) of the window.  */
          start_display (&it, w, pt);
-         move_it_vertically (&it, - h);
+         it.current_y = 0;
+         move_it_vertically_backward (&it, h);
+
+         /* If extra line spacing is present, we may move too far
+            back.  This causes the last line to be only partially
+            visible (which triggers redisplay to recenter that line
+            in the middle), so move forward.
+            But ignore extra line spacing on last line, as it is not
+            considered to be part of the visible height of the line.
+         */
+         h += extra_line_spacing;
+         while (-it.current_y > h)
+           move_it_by_lines (&it, 1, 1);
+
          charpos = IT_CHARPOS (it);
          bytepos = IT_BYTEPOS (it);
        }
@@ -5767,7 +5892,7 @@ save_window_save (window, vector, i)
       p = SAVED_WINDOW_N (vector, i);
       w = XWINDOW (window);
 
-      XSETFASTINT (w->temslot, i++);
+      XSETFASTINT (w->temslot, i); i++;
       p->window = window;
       p->buffer = w->buffer;
       p->left_col = w->left_col;
@@ -5888,7 +6013,8 @@ redirection (see `redirect-frame-focus').  */)
 
 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
        0, UNEVALLED, 0,
-       doc: /* Execute body, preserving window sizes and contents.
+       doc: /* Execute BODY, preserving window sizes and contents.
+Return the value of the last form in BODY.
 Restore which buffer appears in which window, where display starts,
 and the value of point and mark for each window.
 Also restore the choice of selected window.
@@ -5997,9 +6123,9 @@ display marginal areas and the text area.  */)
   struct window *w = decode_window (window);
 
   if (!NILP (left))
-    CHECK_NUMBER (left);
+    CHECK_NATNUM (left);
   if (!NILP (right))
-    CHECK_NUMBER (right);
+    CHECK_NATNUM (right);
 
   if (!EQ (w->left_fringe_width, left)
       || !EQ (w->right_fringe_width, right)
@@ -6059,13 +6185,15 @@ If TYPE is t, use the frame's scroll-bar type.  */)
   struct window *w = decode_window (window);
 
   if (!NILP (width))
-    CHECK_NUMBER (width);
+    {
+      CHECK_NATNUM (width);
 
-  if (XINT (width) == 0)
-    vertical_type = Qnil;
+      if (XINT (width) == 0)
+       vertical_type = Qnil;
+    }
 
   if (!(EQ (vertical_type, Qnil)
-       || EQ (vertical_type, Qleft) 
+       || EQ (vertical_type, Qleft)
        || EQ (vertical_type, Qright)
        || EQ (vertical_type, Qt)))
     error ("Invalid type of vertical scroll bar");
@@ -6114,12 +6242,13 @@ value.  */)
                           Smooth scrolling
  ***********************************************************************/
 
-DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 1, 0,
+DEFUN ("window-vscroll", Fwindow_vscroll, Swindow_vscroll, 0, 2, 0,
        doc: /* Return the amount by which WINDOW is scrolled vertically.
 Use the selected window if WINDOW is nil or omitted.
-Value is a multiple of the canonical character height of WINDOW.  */)
-     (window)
-     Lisp_Object window;
+Normally, value is a multiple of the canonical character height of WINDOW;
+optional second arg PIXELS_P means value is measured in pixels.  */)
+  (window, pixels_p)
+     Lisp_Object window, pixels_p;
 {
   Lisp_Object result;
   struct frame *f;
@@ -6133,7 +6262,9 @@ Value is a multiple of the canonical character height of WINDOW.  */)
   f = XFRAME (w->frame);
 
   if (FRAME_WINDOW_P (f))
-    result = FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll);
+    result = (NILP (pixels_p)
+             ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
+             : make_number (-w->vscroll));
   else
     result = make_number (0);
   return result;
@@ -6141,12 +6272,17 @@ Value is a multiple of the canonical character height of WINDOW.  */)
 
 
 DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
-       2, 2, 0,
+       2, 3, 0,
        doc: /* Set amount by which WINDOW should be scrolled vertically to VSCROLL.
-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;
+WINDOW nil means use the selected window.  Normally, VSCROLL is a
+non-negative multiple of the canonical character height of WINDOW;
+optional third arg PIXELS_P non-nil means that VSCROLL is in pixels.
+If PIXELS-P is nil, VSCROLL may have to be rounded so that it
+corresponds to an integral number of pixels.  The return value is the
+result of this rounding.
+If PIXELS-P is non-nil, the return value is VSCROLL.  */)
+  (window, vscroll, pixels_p)
+     Lisp_Object window, vscroll, pixels_p;
 {
   struct window *w;
   struct frame *f;
@@ -6164,7 +6300,9 @@ multiple of the canonical character height of WINDOW.  */)
     {
       int old_dy = w->vscroll;
 
-      w->vscroll = - FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll);
+      w->vscroll = - (NILP (pixels_p)
+                     ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll)
+                     : XFLOATINT (vscroll));
       w->vscroll = min (w->vscroll, 0);
 
       /* Adjust glyph matrix of the frame if the virtual display
@@ -6176,7 +6314,7 @@ multiple of the canonical character height of WINDOW.  */)
       XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
     }
 
-  return Fwindow_vscroll (window);
+  return Fwindow_vscroll (window, pixels_p);
 }
 
 \f
@@ -6455,7 +6593,9 @@ the buffer; `temp-buffer-show-hook' is not run unless this function runs it.  */
   DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function,
               doc: /* If non-nil, function to call to handle `display-buffer'.
 It will receive two args, the buffer and a flag which if non-nil means
- that the currently selected window is not acceptable.
+that the currently selected window is not acceptable.
+It should choose or create a window, display the specified buffer in it,
+and return the window.
 Commands such as `switch-to-buffer-other-window' and `find-file-other-window'
 work using this function.  */);
   Vdisplay_buffer_function = Qnil;
@@ -6504,9 +6644,10 @@ using `special-display-function'.  See also `special-display-regexps'.
 An element of the list can be a list instead of just a string.
 There are two ways to use a list as an element:
   (BUFFER FRAME-PARAMETERS...)   (BUFFER FUNCTION OTHER-ARGS...)
-In the first case, FRAME-PARAMETERS are used to create the frame.
-In the latter case, FUNCTION is called with BUFFER as the first argument,
-followed by OTHER-ARGS--it can display BUFFER in any way it likes.
+In the first case, the FRAME-PARAMETERS are pairs of the form
+\(PARAMETER . VALUE); these parameter values are used to create the frame.
+In the second case, FUNCTION is called with BUFFER as the first argument,
+followed by the OTHER-ARGS--it can display BUFFER in any way it likes.
 All this is done by the function found in `special-display-function'.
 
 If the specified frame parameters include (same-buffer . t), the
@@ -6529,9 +6670,10 @@ using `special-display-function'.
 An element of the list can be a list instead of just a string.
 There are two ways to use a list as an element:
   (REGEXP FRAME-PARAMETERS...)   (REGEXP FUNCTION OTHER-ARGS...)
-In the first case, FRAME-PARAMETERS are used to create the frame.
-In the latter case, FUNCTION is called with the buffer as first argument,
-followed by OTHER-ARGS--it can display the buffer in any way it likes.
+In the first case, the FRAME-PARAMETERS are pairs of the form
+\(PARAMETER . VALUE); these parameter values are used to create the frame.
+In the second case, FUNCTION is called with BUFFER as the first argument,
+followed by the OTHER-ARGS--it can display the buffer in any way it likes.
 All this is done by the function found in `special-display-function'.
 
 If the specified frame parameters include (same-buffer . t), the
@@ -6597,7 +6739,7 @@ See also `same-window-buffer-names'.  */);
   next_screen_context_lines = 2;
 
   DEFVAR_INT ("split-height-threshold", &split_height_threshold,
-             doc: /* *display-buffer would prefer to split the largest window if this large.
+             doc: /* *A window must be at least this tall to be eligible for splitting by `display-buffer'.
 If there is only one window, it is split regardless of this value.  */);
   split_height_threshold = 500;
 
@@ -6622,9 +6764,11 @@ The selected frame is the one whose configuration has changed.  */);
 
   DEFVAR_BOOL ("window-size-fixed", &window_size_fixed,
               doc: /* Non-nil in a buffer means windows displaying the buffer are fixed-size.
+If the value is`height', then only the window's height is fixed.
+If the value is `width', then only the window's width is fixed.
+Any other non-nil value fixes both the width and the height.
 Emacs won't change the size of any window displaying that buffer,
-unless you explicitly change the size, or Emacs has no other choice.
-This variable automatically becomes buffer-local when set.  */);
+unless you explicitly change the size, or Emacs has no other choice.  */);
   Fmake_variable_buffer_local (Qwindow_size_fixed);
   window_size_fixed = 0;