emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] Changes to emacs/src/window.c [gnus-5_10-branch]


From: Miles Bader
Subject: [Emacs-diffs] Changes to emacs/src/window.c [gnus-5_10-branch]
Date: Sat, 04 Sep 2004 08:16:43 -0400

Index: emacs/src/window.c
diff -c /dev/null emacs/src/window.c:1.472.2.1
*** /dev/null   Sat Sep  4 12:03:42 2004
--- emacs/src/window.c  Sat Sep  4 12:01:19 2004
***************
*** 0 ****
--- 1,6776 ----
+ /* Window creation, deletion and examination for GNU Emacs.
+    Does not include redisplay.
+    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.
+ 
+ GNU Emacs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Emacs; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #include <config.h>
+ #include "lisp.h"
+ #include "buffer.h"
+ #include "keyboard.h"
+ #include "keymap.h"
+ #include "frame.h"
+ #include "window.h"
+ #include "commands.h"
+ #include "indent.h"
+ #include "termchar.h"
+ #include "disptab.h"
+ #include "dispextern.h"
+ #include "blockinput.h"
+ #include "intervals.h"
+ 
+ #ifdef HAVE_X_WINDOWS
+ #include "xterm.h"
+ #endif        /* HAVE_X_WINDOWS */
+ #ifdef WINDOWSNT
+ #include "w32term.h"
+ #endif
+ #ifdef MSDOS
+ #include "msdos.h"
+ #endif
+ #ifdef MAC_OS
+ #include "macterm.h"
+ #endif
+ 
+ 
+ Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
+ Lisp_Object Qwindow_size_fixed;
+ extern Lisp_Object Qleft_margin, Qright_margin;
+ 
+ static int displayed_window_lines P_ ((struct window *));
+ static struct window *decode_window P_ ((Lisp_Object));
+ static int count_windows P_ ((struct window *));
+ static int get_leaf_windows P_ ((struct window *, struct window **, int));
+ static void window_scroll P_ ((Lisp_Object, int, int, int));
+ static void window_scroll_pixel_based P_ ((Lisp_Object, int, int, int));
+ static void window_scroll_line_based P_ ((Lisp_Object, int, int, int));
+ static int window_min_size_1 P_ ((struct window *, int));
+ static int window_min_size P_ ((struct window *, int, int, int *));
+ static void size_window P_ ((Lisp_Object, int, int, int));
+ static 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, 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,
+                                  Lisp_Object));
+ static Lisp_Object next_window P_ ((Lisp_Object, Lisp_Object,
+                                   Lisp_Object, int));
+ static void decode_next_window_args P_ ((Lisp_Object *, Lisp_Object *,
+                                        Lisp_Object *));
+ static int foreach_window_1 P_ ((struct window *,
+                                int (* fn) (struct window *, void *),
+                                void *));
+ static Lisp_Object window_list_1 P_ ((Lisp_Object, Lisp_Object, Lisp_Object));
+ 
+ /* The value of `window-size-fixed'.  */
+ 
+ int window_size_fixed;
+ 
+ /* This is the window in which the terminal's cursor should
+    be left when nothing is being done with it.  This must
+    always be a leaf window, and its buffer is selected by
+    the top level editing loop at the end of each command.
+ 
+    This value is always the same as
+    FRAME_SELECTED_WINDOW (selected_frame).  */
+ 
+ Lisp_Object selected_window;
+ 
+ /* A list of all windows for use by next_window and Fwindow_list.
+    Functions creating or deleting windows should invalidate this cache
+    by setting it to nil.  */
+ 
+ Lisp_Object Vwindow_list;
+ 
+ /* The mini-buffer window of the selected frame.
+    Note that you cannot test for mini-bufferness of an arbitrary window
+    by comparing against this; but you can test for mini-bufferness of
+    the selected window.  */
+ 
+ Lisp_Object minibuf_window;
+ 
+ /* Non-nil means it is the window whose mode line should be
+    shown as the selected window when the minibuffer is selected.  */
+ 
+ Lisp_Object minibuf_selected_window;
+ 
+ /* Non-nil means it is the window for C-M-v to scroll
+    when the mini-buffer is selected.  */
+ 
+ Lisp_Object Vminibuf_scroll_window;
+ 
+ /* Non-nil means this is the buffer whose window C-M-v should scroll.  */
+ 
+ Lisp_Object Vother_window_scroll_buffer;
+ 
+ /* Non-nil means it's function to call to display temp buffers.  */
+ 
+ Lisp_Object Vtemp_buffer_show_function;
+ 
+ /* Non-zero means to use mode-line-inactive face in all windows but the
+    selected-window and the minibuffer-scroll-window when the
+    minibuffer is active.  */
+ int mode_line_in_non_selected_windows;
+ 
+ /* If a window gets smaller than either of these, it is removed. */
+ 
+ EMACS_INT window_min_height;
+ EMACS_INT window_min_width;
+ 
+ /* Nonzero implies Fdisplay_buffer should create windows. */
+ 
+ int pop_up_windows;
+ 
+ /* Nonzero implies make new frames for Fdisplay_buffer.  */
+ 
+ int pop_up_frames;
+ 
+ /* Nonzero means reuse existing frames for displaying buffers.  */
+ 
+ int display_buffer_reuse_frames;
+ 
+ /* Non-nil means use this function instead of default */
+ 
+ Lisp_Object Vpop_up_frame_function;
+ 
+ /* Function to call to handle Fdisplay_buffer.  */
+ 
+ Lisp_Object Vdisplay_buffer_function;
+ 
+ /* Non-nil means that Fdisplay_buffer should even the heights of windows.  */
+ 
+ Lisp_Object Veven_window_heights;
+ 
+ /* List of buffer *names* for buffers that should have their own frames.  */
+ 
+ Lisp_Object Vspecial_display_buffer_names;
+ 
+ /* List of regexps for buffer names that should have their own frames.  */
+ 
+ Lisp_Object Vspecial_display_regexps;
+ 
+ /* Function to pop up a special frame.  */
+ 
+ Lisp_Object Vspecial_display_function;
+ 
+ /* List of buffer *names* for buffers to appear in selected window.  */
+ 
+ Lisp_Object Vsame_window_buffer_names;
+ 
+ /* List of regexps for buffer names to appear in selected window.  */
+ 
+ Lisp_Object Vsame_window_regexps;
+ 
+ /* Hook run at end of temp_output_buffer_show.  */
+ 
+ Lisp_Object Qtemp_buffer_show_hook;
+ 
+ /* Fdisplay_buffer always splits the largest window
+    if that window is more than this high.  */
+ 
+ EMACS_INT split_height_threshold;
+ 
+ /* Number of lines of continuity in scrolling by screenfuls.  */
+ 
+ EMACS_INT next_screen_context_lines;
+ 
+ /* Incremented for each window created.  */
+ 
+ static int sequence_number;
+ 
+ /* Nonzero after init_window_once has finished.  */
+ 
+ static int window_initialized;
+ 
+ /* Hook to run when window config changes.  */
+ 
+ Lisp_Object Qwindow_configuration_change_hook;
+ Lisp_Object Vwindow_configuration_change_hook;
+ 
+ /* Nonzero means scroll commands try to put point
+    at the same screen height as previously.  */
+ 
+ Lisp_Object Vscroll_preserve_screen_position;
+ 
+ #if 0 /* This isn't used anywhere.  */
+ /* Nonzero means we can split a frame even if it is "unsplittable".  */
+ static int inhibit_frame_unsplittable;
+ #endif /* 0 */
+ 
+ extern EMACS_INT scroll_margin;
+ 
+ extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
+ 
+ DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
+        doc: /* Returns t if OBJECT is a window.  */)
+      (object)
+      Lisp_Object object;
+ {
+   return WINDOWP (object) ? Qt : Qnil;
+ }
+ 
+ DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
+        doc: /* Returns t if OBJECT is a window which is currently visible.  
*/)
+      (object)
+      Lisp_Object object;
+ {
+   return WINDOW_LIVE_P (object) ? Qt : Qnil;
+ }
+ 
+ Lisp_Object
+ make_window ()
+ {
+   Lisp_Object val;
+   register struct window *p;
+ 
+   p = allocate_window ();
+   XSETFASTINT (p->sequence_number, ++sequence_number);
+   XSETFASTINT (p->left_col, 0);
+   XSETFASTINT (p->top_line, 0);
+   XSETFASTINT (p->total_lines, 0);
+   XSETFASTINT (p->total_cols, 0);
+   XSETFASTINT (p->hscroll, 0);
+   XSETFASTINT (p->min_hscroll, 0);
+   p->orig_top_line = p->orig_total_lines = Qnil;
+   p->start = Fmake_marker ();
+   p->pointm = Fmake_marker ();
+   XSETFASTINT (p->use_time, 0);
+   p->frame = Qnil;
+   p->display_table = Qnil;
+   p->dedicated = Qnil;
+   p->pseudo_window_p = 0;
+   bzero (&p->cursor, sizeof (p->cursor));
+   bzero (&p->last_cursor, sizeof (p->last_cursor));
+   bzero (&p->phys_cursor, sizeof (p->phys_cursor));
+   p->desired_matrix = p->current_matrix = 0;
+   p->nrows_scale_factor = p->ncols_scale_factor = 1;
+   p->phys_cursor_type = -1;
+   p->phys_cursor_width = -1;
+   p->must_be_updated_p = 0;
+   XSETFASTINT (p->window_end_vpos, 0);
+   XSETFASTINT (p->window_end_pos, 0);
+   p->window_end_valid = Qnil;
+   p->vscroll = 0;
+   XSETWINDOW (val, p);
+   XSETFASTINT (p->last_point, 0);
+   p->frozen_window_start_p = 0;
+   p->height_fixed_p = 0;
+   p->last_cursor_off_p = p->cursor_off_p = 0;
+   p->left_margin_cols = Qnil;
+   p->right_margin_cols = Qnil;
+   p->left_fringe_width = Qnil;
+   p->right_fringe_width = Qnil;
+   p->fringes_outside_margins = Qnil;
+   p->scroll_bar_width = Qnil;
+   p->vertical_scroll_bar_type = Qt;
+   p->overlay_arrow_bitmap = 0;
+ 
+   Vwindow_list = Qnil;
+   return val;
+ }
+ 
+ DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0,
+        doc: /* Return the window that the cursor now appears in and commands 
apply to.  */)
+      ()
+ {
+   return selected_window;
+ }
+ 
+ DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0,
+        doc: /* Return the window used now for minibuffers.
+ If the optional argument FRAME is specified, return the minibuffer window
+ used by that frame.  */)
+      (frame)
+     Lisp_Object frame;
+ {
+   if (NILP (frame))
+     frame = selected_frame;
+   CHECK_LIVE_FRAME (frame);
+   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
+ }
+ 
+ DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 
1, 0,
+        doc: /* Returns non-nil if WINDOW is a minibuffer window.
+ WINDOW defaults to the selected window.  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w = decode_window (window);
+   return MINI_WINDOW_P (w) ? Qt : Qnil;
+ }
+ 
+ 
+ DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
+        Spos_visible_in_window_p, 0, 3, 0,
+        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.
+ 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;
+ {
+   register struct window *w;
+   register int posint;
+   register struct buffer *buf;
+   struct text_pos top;
+   Lisp_Object in_window = Qnil;
+   int fully_p = 1;
+   int x, y;
+ 
+   w = decode_window (window);
+   buf = XBUFFER (w->buffer);
+   SET_TEXT_POS_FROM_MARKER (top, w->start);
+ 
+   if (!NILP (pos))
+     {
+       CHECK_NUMBER_COERCE_MARKER (pos);
+       posint = XINT (pos);
+     }
+   else if (w == XWINDOW (selected_window))
+     posint = PT;
+   else
+     posint = XMARKER (w->pointm)->charpos;
+ 
+   /* 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;
+ }
+ 
+ 
+ static struct window *
+ decode_window (window)
+      register Lisp_Object window;
+ {
+   if (NILP (window))
+     return XWINDOW (selected_window);
+ 
+   CHECK_LIVE_WINDOW (window);
+   return XWINDOW (window);
+ }
+ 
+ static struct window *
+ decode_any_window (window)
+      register Lisp_Object window;
+ {
+   if (NILP (window))
+     return XWINDOW (selected_window);
+ 
+   CHECK_WINDOW (window);
+   return XWINDOW (window);
+ }
+ 
+ DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0,
+        doc: /* Return the buffer that WINDOW is displaying.
+ WINDOW defaults to the selected window.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_window (window)->buffer;
+ }
+ 
+ DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0,
+        doc: /* Return the number of lines in WINDOW (including its mode 
line).  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_any_window (window)->total_lines;
+ }
+ 
+ DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
+        doc: /* Return the number of display columns in WINDOW.
+ This is the width that is usable columns available for text in WINDOW.
+ If you want to find out how many columns WINDOW takes up,
+ use  (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).  */)
+      (window)
+      Lisp_Object window;
+ {
+   return make_number (window_box_text_cols (decode_any_window (window)));
+ }
+ 
+ DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
+        doc: /* Return the number of columns by which WINDOW is scrolled from 
left margin.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_window (window)->hscroll;
+ }
+ 
+ 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.
+ 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.  */)
+      (window, ncol)
+      Lisp_Object window, ncol;
+ {
+   struct window *w = decode_window (window);
+   int hscroll;
+ 
+   CHECK_NUMBER (ncol);
+   hscroll = max (0, XINT (ncol));
+ 
+   /* Prevent redisplay shortcuts when changing the hscroll.  */
+   if (XINT (w->hscroll) != hscroll)
+     XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ 
+   w->hscroll = make_number (hscroll);
+   return ncol;
+ }
+ 
+ DEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
+        Swindow_redisplay_end_trigger, 0, 1, 0,
+        doc: /* Return WINDOW's redisplay end trigger value.
+ See `set-window-redisplay-end-trigger' for more information.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_window (window)->redisplay_end_trigger;
+ }
+ 
+ DEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
+        Sset_window_redisplay_end_trigger, 2, 2, 0,
+        doc: /* Set WINDOW's redisplay end trigger value to VALUE.
+ VALUE should be a buffer position (typically a marker) or nil.
+ If it is a buffer position, then if redisplay in WINDOW reaches a position
+ beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
+ with two arguments: WINDOW, and the end trigger value.
+ Afterwards the end-trigger value is reset to nil.  */)
+      (window, value)
+      register Lisp_Object window, value;
+ {
+   register struct window *w;
+ 
+   w = decode_window (window);
+   w->redisplay_end_trigger = value;
+   return value;
+ }
+ 
+ DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
+        doc: /* Return a list of the edge 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 column occupied by WINDOW,
+ and BOTTOM is one more than the bottommost row occupied by WINDOW.
+ The edges include the space used by the window's scroll bar,
+ display margins, fringes, header line, and mode line, if it has them.
+ To get the edges of the actual text area, use `window-inside-edges'.  */)
+      (window)
+      Lisp_Object window;
+ {
+   register struct window *w = decode_any_window (window);
+ 
+   return Fcons (make_number (WINDOW_LEFT_EDGE_COL (w)),
+        Fcons (make_number (WINDOW_TOP_EDGE_LINE (w)),
+        Fcons (make_number (WINDOW_RIGHT_EDGE_COL (w)),
+        Fcons (make_number (WINDOW_BOTTOM_EDGE_LINE (w)),
+               Qnil))));
+ }
+ 
+ DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 
0,
+        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 occupied by WINDOW,
+ and BOTTOM is one more than the bottommost y position occupied by WINDOW.
+ The pixel edges include the space used by the window's scroll bar,
+ display margins, fringes, header line, and mode line, if it has them.
+ To get the edges of the actual text area, use `window-inside-pixel-edges'.  
*/)
+      (window)
+      Lisp_Object window;
+ {
+   register struct window *w = decode_any_window (window);
+ 
+   return Fcons (make_number (WINDOW_LEFT_EDGE_X (w)),
+        Fcons (make_number (WINDOW_TOP_EDGE_Y (w)),
+        Fcons (make_number (WINDOW_RIGHT_EDGE_X (w)),
+        Fcons (make_number (WINDOW_BOTTOM_EDGE_Y (w)),
+               Qnil))));
+ }
+ 
+ DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 
1, 0,
+        doc: /* Return a list of the edge 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 column used by text in WINDOW,
+ and BOTTOM is one more than the bottommost row used by text in WINDOW.
+ The inside edges do not include the space used by the window's scroll bar,
+ display margins, fringes, header line, and/or mode line.  */)
+      (window)
+      Lisp_Object window;
+ {
+   register struct window *w = decode_any_window (window);
+ 
+   return list4 (make_number (WINDOW_BOX_LEFT_EDGE_COL (w)
+                            + WINDOW_LEFT_MARGIN_COLS (w)
+                            + WINDOW_LEFT_FRINGE_COLS (w)),
+               make_number (WINDOW_TOP_EDGE_LINE (w)
+                            + WINDOW_HEADER_LINE_LINES (w)),
+               make_number (WINDOW_RIGHT_EDGE_COL (w)
+                            - WINDOW_RIGHT_MARGIN_COLS (w)
+                            - WINDOW_RIGHT_FRINGE_COLS (w)),
+               make_number (WINDOW_BOTTOM_EDGE_LINE (w)
+                            - WINDOW_MODE_LINE_LINES (w)));
+ }
+ 
+ DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, 
Swindow_inside_pixel_edges, 0, 1, 0,
+        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.
+ The inside edges do not include the space used by the window's scroll bar,
+ display margins, fringes, header line, and/or mode line.  */)
+      (window)
+      Lisp_Object window;
+ {
+   register struct window *w = decode_any_window (window);
+ 
+   return list4 (make_number (WINDOW_BOX_LEFT_EDGE_X (w)
+                            + WINDOW_LEFT_MARGIN_WIDTH (w)
+                            + WINDOW_LEFT_FRINGE_WIDTH (w)),
+               make_number (WINDOW_TOP_EDGE_Y (w)
+                            + WINDOW_HEADER_LINE_HEIGHT (w)),
+               make_number (WINDOW_RIGHT_EDGE_X (w)
+                            - WINDOW_RIGHT_MARGIN_WIDTH (w)
+                            - WINDOW_RIGHT_FRINGE_WIDTH (w)),
+               make_number (WINDOW_BOTTOM_EDGE_Y (w)
+                            - WINDOW_MODE_LINE_HEIGHT (w)));
+ }
+ 
+ /* Test if the character at column *X, row *Y is within window W.
+    If it is not, return ON_NOTHING;
+    if it is in the window's text area,
+       set *x and *y to its location relative to the upper left corner
+          of the window, and
+       return ON_TEXT;
+    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
+       to window-relative coordinates;
+    if it is in the marginal area to the left/right of the window,
+       return ON_LEFT_MARGIN or ON_RIGHT_MARGIN, and convert *X and *Y
+       to window-relative coordinates.
+ 
+    X and Y are frame relative pixel coordinates.  */
+ 
+ static enum window_part
+ coordinates_in_window (w, x, y)
+      register struct window *w;
+      register int *x, *y;
+ {
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   int left_x, right_x, top_y, bottom_y;
+   enum window_part part;
+   int ux = FRAME_COLUMN_WIDTH (f);
+   int x0 = WINDOW_LEFT_EDGE_X (w);
+   int x1 = WINDOW_RIGHT_EDGE_X (w);
+   /* The width of the area where the vertical line can be dragged.
+      (Between mode lines for instance.  */
+   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)
+     {
+       left_x = 0;
+       right_x = WINDOW_TOTAL_WIDTH (w) - 1;
+       top_y = WINDOW_TOP_EDGE_Y (w);
+       bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
+     }
+   else
+     {
+       left_x = WINDOW_BOX_LEFT_EDGE_X (w);
+       right_x = WINDOW_BOX_RIGHT_EDGE_X (w) - 1;
+       top_y = WINDOW_TOP_EDGE_Y (w);
+       bottom_y = WINDOW_BOTTOM_EDGE_Y (w);
+     }
+ 
+   /* Outside any interesting row?  */
+   if (*y < top_y || *y >= bottom_y)
+     return ON_NOTHING;
+ 
+   /* On the mode line or header line?  If it's near the start of
+      the mode or header line of window that's has a horizontal
+      sibling, say it's on the vertical line.  That's to be able
+      to resize windows horizontally in case we're using toolkit
+      scroll bars.  */
+ 
+   if (WINDOW_WANTS_MODELINE_P (w)
+       && *y >= bottom_y - CURRENT_MODE_LINE_HEIGHT (w))
+     {
+       part = ON_MODE_LINE;
+ 
+     header_vertical_border_check:
+       /* We're somewhere on the mode line.  We consider the place
+        between mode lines of horizontally adjacent mode lines
+        as the vertical border.    If scroll bars on the left,
+        return the right window.  */
+       if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+         || WINDOW_RIGHTMOST_P (w))
+       {
+         if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
+           return ON_VERTICAL_BORDER;
+       }
+       else
+       {
+         if (abs (*x - x1) < grabbable_width)
+           return ON_VERTICAL_BORDER;
+       }
+ 
+       /* Convert X and Y to window relative coordinates.
+        Mode line starts at left edge of window.  */
+       *x -= x0;
+       *y -= top_y;
+       return part;
+     }
+ 
+   if (WINDOW_WANTS_HEADER_LINE_P (w)
+       && *y < top_y + CURRENT_HEADER_LINE_HEIGHT (w))
+     {
+       part = ON_HEADER_LINE;
+       goto header_vertical_border_check;
+     }
+ 
+   /* Outside any interesting column?  */
+   if (*x < left_x || *x > right_x)
+     return ON_SCROLL_BAR;
+ 
+   lmargin_width = window_box_width (w, LEFT_MARGIN_AREA);
+   rmargin_width = window_box_width (w, RIGHT_MARGIN_AREA);
+ 
+   text_left = window_box_left (w, TEXT_AREA);
+   text_right = text_left + window_box_width (w, TEXT_AREA);
+ 
+   if (FRAME_WINDOW_P (f))
+     {
+       if (!w->pseudo_window_p
+         && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
+         && !WINDOW_RIGHTMOST_P (w)
+         && (abs (*x - right_x) < grabbable_width))
+       return ON_VERTICAL_BORDER;
+     }
+   else
+     {
+       /* Need to say "*x > right_x" rather than >=, since on character
+        terminals, the vertical line's x coordinate is right_x.  */
+       if (!w->pseudo_window_p
+         && !WINDOW_RIGHTMOST_P (w)
+         && *x > right_x - ux)
+       {
+         /* On the border on the right side of the window?  Assume that
+            this area begins at RIGHT_X minus a canonical char width.  */
+         return ON_VERTICAL_BORDER;
+       }
+     }
+ 
+   if (*x < text_left)
+     {
+       if (lmargin_width > 0
+         && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+             ? (*x >= left_x + WINDOW_LEFT_FRINGE_WIDTH (w))
+             : (*x < left_x + lmargin_width)))
+       {
+         *x -= left_x;
+         if (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+           *x -= WINDOW_LEFT_FRINGE_WIDTH (w);
+         *y -= top_y;
+         return ON_LEFT_MARGIN;
+       }
+ 
+       /* Convert X and Y to window-relative pixel coordinates.  */
+       *x -= left_x;
+       *y -= top_y;
+       return ON_LEFT_FRINGE;
+     }
+ 
+   if (*x >= text_right)
+     {
+       if (rmargin_width > 0
+         && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+             ? (*x < right_x - WINDOW_RIGHT_FRINGE_WIDTH (w))
+             : (*x >= right_x - rmargin_width)))
+       {
+         *x -= right_x;
+         if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
+           *x -= WINDOW_RIGHT_FRINGE_WIDTH (w);
+         *y -= top_y;
+         return ON_RIGHT_MARGIN;
+       }
+ 
+       /* Convert X and Y to window-relative pixel coordinates.  */
+       *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
+       *y -= top_y;
+       return ON_RIGHT_FRINGE;
+     }
+ 
+   /* Everything special ruled out - must be on text area */
+   *x -= left_x + WINDOW_LEFT_FRINGE_WIDTH (w);
+   *y -= top_y;
+   return ON_TEXT;
+ }
+ 
+ 
+ DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
+        Scoordinates_in_window_p, 2, 2, 0,
+        doc: /* Return non-nil if COORDINATES are in WINDOW.
+ COORDINATES is a cons of the form (X . Y), X and Y being distances
+ measured in characters from the upper-left corner of the frame.
+ \(0 .  0) denotes the character in the upper left corner of the
+ frame.
+ 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 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.
+ If they are in the windows's left or right marginal areas, `left-margin'\n\
+   or `right-margin' is returned.  */)
+      (coordinates, window)
+      register Lisp_Object coordinates, window;
+ {
+   struct window *w;
+   struct frame *f;
+   int x, y;
+   Lisp_Object lx, ly;
+ 
+   CHECK_WINDOW (window);
+   w = XWINDOW (window);
+   f = XFRAME (w->frame);
+   CHECK_CONS (coordinates);
+   lx = Fcar (coordinates);
+   ly = Fcdr (coordinates);
+   CHECK_NUMBER_OR_FLOAT (lx);
+   CHECK_NUMBER_OR_FLOAT (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))
+     {
+     case ON_NOTHING:
+       return Qnil;
+ 
+     case ON_TEXT:
+       /* X and Y are now window relative pixel coordinates.  Convert
+        them to canonical char units before returning them.  */
+       return Fcons (FRAME_CANON_X_FROM_PIXEL_X (f, x),
+                   FRAME_CANON_Y_FROM_PIXEL_Y (f, y));
+ 
+     case ON_MODE_LINE:
+       return Qmode_line;
+ 
+     case ON_VERTICAL_BORDER:
+       return Qvertical_line;
+ 
+     case ON_HEADER_LINE:
+       return Qheader_line;
+ 
+     case ON_LEFT_FRINGE:
+       return Qleft_fringe;
+ 
+     case ON_RIGHT_FRINGE:
+       return Qright_fringe;
+ 
+     case ON_LEFT_MARGIN:
+       return Qleft_margin;
+ 
+     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 ();
+     }
+ }
+ 
+ 
+ /* Callback for foreach_window, used in window_from_coordinates.
+    Check if window W contains coordinates specified by USER_DATA which
+    is actually a pointer to a struct check_window_data CW.
+ 
+    Check if window W contains coordinates *CW->x and *CW->y.  If it
+    does, return W in *CW->window, as Lisp_Object, and return in
+    *CW->part the part of the window under coordinates *X,*Y.  Return
+    zero from this function to stop iterating over windows.  */
+ 
+ struct check_window_data
+ {
+   Lisp_Object *window;
+   int *x, *y;
+   enum window_part *part;
+ };
+ 
+ static int
+ check_window_containing (w, user_data)
+      struct window *w;
+      void *user_data;
+ {
+   struct check_window_data *cw = (struct check_window_data *) user_data;
+   enum window_part found;
+   int continue_p = 1;
+ 
+   found = coordinates_in_window (w, cw->x, cw->y);
+   if (found != ON_NOTHING)
+     {
+       *cw->part = found;
+       XSETWINDOW (*cw->window, w);
+       continue_p = 0;
+     }
+ 
+   return continue_p;
+ }
+ 
+ 
+ /* Find the window containing frame-relative pixel position X/Y and
+    return it as a Lisp_Object.
+ 
+    If X, Y is on one of the window's special `window_part' elements,
+    set *PART to the id of that element, and return X and Y converted
+    to window relative coordinates in WX and WY.
+ 
+    If there is no window under X, Y return nil and leave *PART
+    unmodified.  TOOL_BAR_P non-zero means detect tool-bar windows.
+ 
+    This function was previously implemented with a loop cycling over
+    windows with Fnext_window, and starting with the frame's selected
+    window.  It turned out that this doesn't work with an
+    implementation of next_window using Vwindow_list, because
+    FRAME_SELECTED_WINDOW (F) is not always contained in the window
+    tree of F when this function is called asynchronously from
+    note_mouse_highlight.  The original loop didn't terminate in this
+    case.  */
+ 
+ Lisp_Object
+ window_from_coordinates (f, x, y, part, wx, wy, tool_bar_p)
+      struct frame *f;
+      int x, y;
+      enum window_part *part;
+      int *wx, *wy;
+      int tool_bar_p;
+ {
+   Lisp_Object window;
+   struct check_window_data cw;
+   enum window_part dummy;
+ 
+   if (part == 0)
+     part = &dummy;
+ 
+   window = Qnil;
+   cw.window = &window, cw.x = &x, cw.y = &y; cw.part = part;
+   foreach_window (f, check_window_containing, &cw);
+ 
+   /* If not found above, see if it's in the tool bar window, if a tool
+      bar exists.  */
+   if (NILP (window)
+       && tool_bar_p
+       && WINDOWP (f->tool_bar_window)
+       && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0
+       && (coordinates_in_window (XWINDOW (f->tool_bar_window), &x, &y)
+         != ON_NOTHING))
+     {
+       *part = ON_TEXT;
+       window = f->tool_bar_window;
+     }
+ 
+   if (wx) *wx = x;
+   if (wy) *wy = y;
+ 
+   return window;
+ }
+ 
+ DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
+        doc: /* Return window containing coordinates X and Y on FRAME.
+ If omitted, FRAME defaults to the currently selected frame.
+ The top left corner of the frame is considered to be row 0,
+ column 0.  */)
+      (x, y, frame)
+      Lisp_Object x, y, frame;
+ {
+   struct frame *f;
+ 
+   if (NILP (frame))
+     frame = selected_frame;
+   CHECK_LIVE_FRAME (frame);
+   f = XFRAME (frame);
+ 
+   /* Check that arguments are integers or floats.  */
+   CHECK_NUMBER_OR_FLOAT (x);
+   CHECK_NUMBER_OR_FLOAT (y);
+ 
+   return window_from_coordinates (f,
+                                 (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);
+ }
+ 
+ DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0,
+        doc: /* Return current value of point in WINDOW.
+ For a nonselected window, this is the value point would have
+ if that window were selected.
+ 
+ Note that, when WINDOW is the selected window and its buffer
+ is also currently selected, the value returned is the same as (point).
+ It would be more strictly correct to return the `top-level' value
+ of point, outside of any save-excursion forms.
+ But that is hard to define.  */)
+      (window)
+      Lisp_Object window;
+ {
+   register struct window *w = decode_window (window);
+ 
+   if (w == XWINDOW (selected_window)
+       && current_buffer == XBUFFER (w->buffer))
+     return Fpoint ();
+   return Fmarker_position (w->pointm);
+ }
+ 
+ DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
+        doc: /* Return position at which display currently starts in WINDOW.
+ This is updated by redisplay or by calling `set-window-start'.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return Fmarker_position (decode_window (window)->start);
+ }
+ 
+ /* This is text temporarily removed from the doc string below.
+ 
+ This function returns nil if the position is not currently known.
+ That happens when redisplay is preempted and doesn't finish.
+ If in that case you want to compute where the end of the window would
+ have been if redisplay had finished, do this:
+     (save-excursion
+       (goto-char (window-start window))
+       (vertical-motion (1- (window-height window)) window)
+       (point))")  */
+ 
+ DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
+        doc: /* Return position at which display currently ends in WINDOW.
+ 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)
+      Lisp_Object window, update;
+ {
+   Lisp_Object value;
+   struct window *w = decode_window (window);
+   Lisp_Object buf;
+ 
+   buf = w->buffer;
+   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.
+      The user can compute it with vertical-motion if he wants to.
+      It would be nicer to do it automatically,
+      but that's so slow that it would probably bother people.  */
+   if (NILP (w->window_end_valid))
+     return Qnil;
+ #endif
+ 
+   if (! NILP (update)
+       && ! (! NILP (w->window_end_valid)
+           && XFASTINT (w->last_modified) >= MODIFF))
+     {
+       struct text_pos startp;
+       struct it it;
+       struct buffer *old_buffer = NULL, *b = XBUFFER (buf);
+ 
+       /* In case W->start is out of the range, use something
+          reasonable.  This situation occurred when loading a file with
+          `-l' containing a call to `rmail' with subsequent other
+          commands.  At the end, W->start happened to be BEG, while
+          rmail had already narrowed the buffer.  */
+       if (XMARKER (w->start)->charpos < BEGV)
+       SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
+       else if (XMARKER (w->start)->charpos > ZV)
+       SET_TEXT_POS (startp, ZV, ZV_BYTE);
+       else
+       SET_TEXT_POS_FROM_MARKER (startp, w->start);
+ 
+       /* Cannot use Fvertical_motion because that function doesn't
+        cope with variable-height lines.  */
+       if (b != current_buffer)
+       {
+         old_buffer = current_buffer;
+         set_buffer_internal (b);
+       }
+ 
+       start_display (&it, w, startp);
+       move_it_vertically (&it, window_box_height (w));
+       if (it.current_y < it.last_visible_y)
+       move_it_past_eol (&it);
+       value = make_number (IT_CHARPOS (it));
+ 
+       if (old_buffer)
+       set_buffer_internal (old_buffer);
+     }
+   else
+     XSETINT (value, BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+ 
+   return value;
+ }
+ 
+ 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.
+ Return POS.  */)
+      (window, pos)
+      Lisp_Object window, pos;
+ {
+   register struct window *w = decode_window (window);
+ 
+   CHECK_NUMBER_COERCE_MARKER (pos);
+   if (w == XWINDOW (selected_window)
+       && XBUFFER (w->buffer) == current_buffer)
+     Fgoto_char (pos);
+   else
+     set_marker_restricted (w->pointm, pos, w->buffer);
+ 
+   /* We have to make sure that redisplay updates the window to show
+      the new value of point.  */
+   if (!EQ (window, selected_window))
+     ++windows_or_buffers_changed;
+ 
+   return pos;
+ }
+ 
+ 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)
+      Lisp_Object window, pos, noforce;
+ {
+   register struct window *w = decode_window (window);
+ 
+   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;
+   if (NILP (noforce))
+     w->force_start = Qt;
+   w->update_mode_line = Qt;
+   XSETFASTINT (w->last_modified, 0);
+   XSETFASTINT (w->last_overlay_modified, 0);
+   if (!EQ (window, selected_window))
+     windows_or_buffers_changed++;
+ 
+   return pos;
+ }
+ 
+ DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
+        1, 1, 0,
+        doc: /* Return WINDOW's dedicated object, usually t or nil.
+ See also `set-window-dedicated-p'.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_window (window)->dedicated;
+ }
+ 
+ DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
+        Sset_window_dedicated_p, 2, 2, 0,
+        doc: /* Control whether WINDOW is dedicated to the buffer it displays.
+ If it is dedicated, Emacs will not automatically change
+ which buffer appears in it.
+ The second argument is the new value for the dedication flag;
+ non-nil means yes. */)
+      (window, arg)
+      Lisp_Object window, arg;
+ {
+   register struct window *w = decode_window (window);
+ 
+   w->dedicated = arg;
+ 
+   return w->dedicated;
+ }
+ 
+ DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table,
+        0, 1, 0,
+        doc: /* Return the display-table that WINDOW is using.  */)
+      (window)
+      Lisp_Object window;
+ {
+   return decode_window (window)->display_table;
+ }
+ 
+ /* Get the display table for use on window W.  This is either W's
+    display table or W's buffer's display table.  Ignore the specified
+    tables if they are not valid; if no valid table is specified,
+    return 0.  */
+ 
+ struct Lisp_Char_Table *
+ window_display_table (w)
+      struct window *w;
+ {
+   struct Lisp_Char_Table *dp = NULL;
+ 
+   if (DISP_TABLE_P (w->display_table))
+     dp = XCHAR_TABLE (w->display_table);
+   else if (BUFFERP (w->buffer))
+     {
+       struct buffer *b = XBUFFER (w->buffer);
+ 
+       if (DISP_TABLE_P (b->display_table))
+       dp = XCHAR_TABLE (b->display_table);
+       else if (DISP_TABLE_P (Vstandard_display_table))
+       dp = XCHAR_TABLE (Vstandard_display_table);
+     }
+ 
+   return dp;
+ }
+ 
+ DEFUN ("set-window-display-table", Fset_window_display_table, 
Sset_window_display_table, 2, 2, 0,
+        doc: /* Set WINDOW's display-table to TABLE.  */)
+      (window, table)
+      register Lisp_Object window, table;
+ {
+   register struct window *w;
+ 
+   w = decode_window (window);
+   w->display_table = table;
+   return table;
+ }
+ 
+ /* Record info on buffer window w is displaying
+    when it is about to cease to display that buffer.  */
+ static void
+ unshow_buffer (w)
+      register struct window *w;
+ {
+   Lisp_Object buf;
+   struct buffer *b;
+ 
+   buf = w->buffer;
+   b = XBUFFER (buf);
+   if (b != XMARKER (w->pointm)->buffer)
+     abort ();
+ 
+ #if 0
+   if (w == XWINDOW (selected_window)
+       || ! EQ (buf, XWINDOW (selected_window)->buffer))
+     /* Do this except when the selected window's buffer
+        is being removed from some other window.  */
+ #endif
+     /* last_window_start records the start position that this buffer
+        had in the last window to be disconnected from it.
+        Now that this statement is unconditional,
+        it is possible for the buffer to be displayed in the
+        selected window, while last_window_start reflects another
+        window which was recently showing the same buffer.
+        Some people might say that might be a good thing.  Let's see.  */
+     b->last_window_start = marker_position (w->start);
+ 
+   /* Point in the selected window's buffer
+      is actually stored in that buffer, and the window's pointm isn't used.
+      So don't clobber point in that buffer.  */
+   if (! EQ (buf, XWINDOW (selected_window)->buffer)
+       /* This line helps to fix Horsley's testbug.el bug.  */
+       && !(WINDOWP (b->last_selected_window)
+          && w != XWINDOW (b->last_selected_window)
+          && EQ (buf, XWINDOW (b->last_selected_window)->buffer)))
+     temp_set_point_both (b,
+                        clip_to_bounds (BUF_BEGV (b),
+                                        XMARKER (w->pointm)->charpos,
+                                        BUF_ZV (b)),
+                        clip_to_bounds (BUF_BEGV_BYTE (b),
+                                        marker_byte_position (w->pointm),
+                                        BUF_ZV_BYTE (b)));
+ 
+   if (WINDOWP (b->last_selected_window)
+       && w == XWINDOW (b->last_selected_window))
+     b->last_selected_window = Qnil;
+ }
+ 
+ /* Put replacement into the window structure in place of old. */
+ static void
+ replace_window (old, replacement)
+      Lisp_Object old, replacement;
+ {
+   register Lisp_Object tem;
+   register struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
+ 
+   /* If OLD is its frame's root_window, then replacement is the new
+      root_window for that frame.  */
+ 
+   if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
+     FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
+ 
+   p->left_col = o->left_col;
+   p->top_line = o->top_line;
+   p->total_cols = o->total_cols;
+   p->total_lines = o->total_lines;
+   p->desired_matrix = p->current_matrix = 0;
+   p->vscroll = 0;
+   bzero (&p->cursor, sizeof (p->cursor));
+   bzero (&p->last_cursor, sizeof (p->last_cursor));
+   bzero (&p->phys_cursor, sizeof (p->phys_cursor));
+   p->phys_cursor_type = -1;
+   p->phys_cursor_width = -1;
+   p->must_be_updated_p = 0;
+   p->pseudo_window_p = 0;
+   XSETFASTINT (p->window_end_vpos, 0);
+   XSETFASTINT (p->window_end_pos, 0);
+   p->window_end_valid = Qnil;
+   p->frozen_window_start_p = 0;
+   p->orig_top_line = p->orig_total_lines = Qnil;
+ 
+   p->next = tem = o->next;
+   if (!NILP (tem))
+     XWINDOW (tem)->prev = replacement;
+ 
+   p->prev = tem = o->prev;
+   if (!NILP (tem))
+     XWINDOW (tem)->next = replacement;
+ 
+   p->parent = tem = o->parent;
+   if (!NILP (tem))
+     {
+       if (EQ (XWINDOW (tem)->vchild, old))
+       XWINDOW (tem)->vchild = replacement;
+       if (EQ (XWINDOW (tem)->hchild, old))
+       XWINDOW (tem)->hchild = replacement;
+     }
+ 
+ /*** Here, if replacement is a vertical combination
+ and so is its new parent, we should make replacement's
+ children be children of that parent instead.  ***/
+ }
+ 
+ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
+        doc: /* Remove WINDOW from the display.  Default is selected window.  
*/)
+      (window)
+      register Lisp_Object window;
+ {
+   delete_window (window);
+ 
+   if (! NILP (Vwindow_configuration_change_hook)
+       && ! NILP (Vrun_hooks))
+     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+ 
+   return Qnil;
+ }
+ 
+ void
+ delete_window (window)
+      register Lisp_Object window;
+ {
+   register Lisp_Object tem, parent, sib;
+   register struct window *p;
+   register struct window *par;
+   struct frame *f;
+ 
+   /* Because this function is called by other C code on non-leaf
+      windows, the CHECK_LIVE_WINDOW macro would choke inappropriately,
+      so we can't decode_window here.  */
+   if (NILP (window))
+     window = selected_window;
+   else
+     CHECK_WINDOW (window);
+   p = XWINDOW (window);
+ 
+   /* It's okay to delete an already-deleted window.  */
+   if (NILP (p->buffer)
+       && NILP (p->hchild)
+       && NILP (p->vchild))
+     return;
+ 
+   parent = p->parent;
+   if (NILP (parent))
+     error ("Attempt to delete minibuffer or sole ordinary window");
+   par = XWINDOW (parent);
+ 
+   windows_or_buffers_changed++;
+   Vwindow_list = Qnil;
+   f = XFRAME (WINDOW_FRAME (p));
+   FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+ 
+   /* Are we trying to delete any frame's selected window?  */
+   {
+     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.  */
+     swindow = FRAME_SELECTED_WINDOW (f);
+ 
+     while (1)
+       {
+       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;
+       /* 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 we need to change SWINDOW, do it.  */
+     if (! EQ (swindow, FRAME_SELECTED_WINDOW (f)))
+       {
+       /* 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 (FRAME_SELECTED_WINDOW (f), selected_window))
+         Fselect_window (swindow, Qnil);
+       else
+         FRAME_SELECTED_WINDOW (f) = swindow;
+       }
+   }
+ 
+   tem = p->buffer;
+   /* tem is null for dummy parent windows
+      (which have inferiors but not any contents themselves) */
+   if (!NILP (tem))
+     {
+       unshow_buffer (p);
+       unchain_marker (XMARKER (p->pointm));
+       unchain_marker (XMARKER (p->start));
+     }
+ 
+   /* Free window glyph matrices.  It is sure that they are allocated
+      again when ADJUST_GLYPHS is called.  Block input so that expose
+      events and other events that access glyph matrices are not
+      processed while we are changing them.  */
+   BLOCK_INPUT;
+   free_window_matrices (XWINDOW (FRAME_ROOT_WINDOW (f)));
+ 
+   tem = p->next;
+   if (!NILP (tem))
+     XWINDOW (tem)->prev = p->prev;
+ 
+   tem = p->prev;
+   if (!NILP (tem))
+     XWINDOW (tem)->next = p->next;
+ 
+   if (EQ (window, par->hchild))
+     par->hchild = p->next;
+   if (EQ (window, par->vchild))
+     par->vchild = p->next;
+ 
+   /* Find one of our siblings to give our space to.  */
+   sib = p->prev;
+   if (NILP (sib))
+     {
+       /* If p gives its space to its next sibling, that sibling needs
+        to have its top/left side pulled back to where p's is.
+        set_window_{height,width} will re-position the sibling's
+        children.  */
+       sib = p->next;
+       XWINDOW (sib)->top_line = p->top_line;
+       XWINDOW (sib)->left_col = p->left_col;
+     }
+ 
+   /* Stretch that sibling.  */
+   if (!NILP (par->vchild))
+     set_window_height (sib,
+                      XFASTINT (XWINDOW (sib)->total_lines) + XFASTINT 
(p->total_lines),
+                      1);
+   if (!NILP (par->hchild))
+     set_window_width (sib,
+                     XFASTINT (XWINDOW (sib)->total_cols) + XFASTINT 
(p->total_cols),
+                     1);
+ 
+   /* If parent now has only one child,
+      put the child into the parent's place.  */
+   tem = par->hchild;
+   if (NILP (tem))
+     tem = par->vchild;
+   if (NILP (XWINDOW (tem)->next))
+     replace_window (parent, tem);
+ 
+   /* Since we may be deleting combination windows, we must make sure that
+      not only p but all its children have been marked as deleted.  */
+   if (! NILP (p->hchild))
+     delete_all_subwindows (XWINDOW (p->hchild));
+   else if (! NILP (p->vchild))
+     delete_all_subwindows (XWINDOW (p->vchild));
+ 
+   /* Mark this window as deleted.  */
+   p->buffer = p->hchild = p->vchild = Qnil;
+ 
+   /* Adjust glyph matrices. */
+   adjust_glyphs (f);
+   UNBLOCK_INPUT;
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                            Window List
+  ***********************************************************************/
+ 
+ /* Add window W to *USER_DATA.  USER_DATA is actually a Lisp_Object
+    pointer.  This is a callback function for foreach_window, used in
+    function window_list.  */
+ 
+ static int
+ add_window_to_list (w, user_data)
+      struct window *w;
+      void *user_data;
+ {
+   Lisp_Object *list = (Lisp_Object *) user_data;
+   Lisp_Object window;
+   XSETWINDOW (window, w);
+   *list = Fcons (window, *list);
+   return 1;
+ }
+ 
+ 
+ /* Return a list of all windows, for use by next_window.  If
+    Vwindow_list is a list, return that list.  Otherwise, build a new
+    list, cache it in Vwindow_list, and return that.  */
+ 
+ static Lisp_Object
+ window_list ()
+ {
+   if (!CONSP (Vwindow_list))
+     {
+       Lisp_Object tail;
+ 
+       Vwindow_list = Qnil;
+       for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
+       {
+         Lisp_Object args[2];
+ 
+         /* We are visiting windows in canonical order, and add
+            new windows at the front of args[1], which means we
+            have to reverse this list at the end.  */
+         args[1] = Qnil;
+         foreach_window (XFRAME (XCAR (tail)), add_window_to_list, &args[1]);
+         args[0] = Vwindow_list;
+         args[1] = Fnreverse (args[1]);
+         Vwindow_list = Fnconc (2, args);
+       }
+     }
+ 
+   return Vwindow_list;
+ }
+ 
+ 
+ /* Value is non-zero if WINDOW satisfies the constraints given by
+    OWINDOW, MINIBUF and ALL_FRAMES.
+ 
+    MINIBUF    t means WINDOW may be minibuffer windows.
+               `lambda' means WINDOW may not be a minibuffer window.
+               a window means a specific minibuffer window
+ 
+    ALL_FRAMES t means search all frames,
+               nil means search just current frame,
+               `visible' means search just visible frames,
+               0 means search visible and iconified frames,
+               a window means search the frame that window belongs to,
+               a frame means consider windows on that frame, only.  */
+ 
+ static int
+ candidate_window_p (window, owindow, minibuf, all_frames)
+      Lisp_Object window, owindow, minibuf, all_frames;
+ {
+   struct window *w = XWINDOW (window);
+   struct frame *f = XFRAME (w->frame);
+   int candidate_p = 1;
+ 
+   if (!BUFFERP (w->buffer))
+     candidate_p = 0;
+   else if (MINI_WINDOW_P (w)
+            && (EQ (minibuf, Qlambda)
+              || (WINDOWP (minibuf) && !EQ (minibuf, window))))
+     {
+       /* If MINIBUF is `lambda' don't consider any mini-windows.
+          If it is a window, consider only that one.  */
+       candidate_p = 0;
+     }
+   else if (EQ (all_frames, Qt))
+     candidate_p = 1;
+   else if (NILP (all_frames))
+     {
+       xassert (WINDOWP (owindow));
+       candidate_p = EQ (w->frame, XWINDOW (owindow)->frame);
+     }
+   else if (EQ (all_frames, Qvisible))
+     {
+       FRAME_SAMPLE_VISIBILITY (f);
+       candidate_p = FRAME_VISIBLE_P (f);
+     }
+   else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
+     {
+       FRAME_SAMPLE_VISIBILITY (f);
+       candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
+     }
+   else if (WINDOWP (all_frames))
+     candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
+                  || EQ (XWINDOW (all_frames)->frame, w->frame)
+                  || EQ (XWINDOW (all_frames)->frame, FRAME_FOCUS_FRAME (f)));
+   else if (FRAMEP (all_frames))
+     candidate_p = EQ (all_frames, w->frame);
+ 
+   return candidate_p;
+ }
+ 
+ 
+ /* Decode arguments as allowed by Fnext_window, Fprevious_window, and
+    Fwindow_list.  See there for the meaning of WINDOW, MINIBUF, and
+    ALL_FRAMES.  */
+ 
+ static void
+ decode_next_window_args (window, minibuf, all_frames)
+      Lisp_Object *window, *minibuf, *all_frames;
+ {
+   if (NILP (*window))
+     *window = selected_window;
+   else
+     CHECK_LIVE_WINDOW (*window);
+ 
+   /* MINIBUF nil may or may not include minibuffers.  Decide if it
+      does.  */
+   if (NILP (*minibuf))
+     *minibuf = minibuf_level ? minibuf_window : Qlambda;
+   else if (!EQ (*minibuf, Qt))
+     *minibuf = Qlambda;
+ 
+   /* Now *MINIBUF can be t => count all minibuffer windows, `lambda'
+      => count none of them, or a specific minibuffer window (the
+      active one) to count.  */
+ 
+   /* ALL_FRAMES nil doesn't specify which frames to include.  */
+   if (NILP (*all_frames))
+     *all_frames = (!EQ (*minibuf, Qlambda)
+                  ? FRAME_MINIBUF_WINDOW (XFRAME (XWINDOW (*window)->frame))
+                  : Qnil);
+   else if (EQ (*all_frames, Qvisible))
+     ;
+   else if (XFASTINT (*all_frames) == 0)
+     ;
+   else if (FRAMEP (*all_frames))
+     ;
+   else if (!EQ (*all_frames, Qt))
+     *all_frames = Qnil;
+ 
+   /* Now *ALL_FRAMES is t meaning search all frames, nil meaning
+      search just current frame, `visible' meaning search just visible
+      frames, 0 meaning search visible and iconified frames, or a
+      window, meaning search the frame that window belongs to, or a
+      frame, meaning consider windows on that frame, only.  */
+ }
+ 
+ 
+ /* Return the next or previous window of WINDOW in canonical ordering
+    of windows.  NEXT_P non-zero means return the next window.  See the
+    documentation string of next-window for the meaning of MINIBUF and
+    ALL_FRAMES.  */
+ 
+ static Lisp_Object
+ next_window (window, minibuf, all_frames, next_p)
+      Lisp_Object window, minibuf, all_frames;
+      int next_p;
+ {
+   decode_next_window_args (&window, &minibuf, &all_frames);
+ 
+   /* If ALL_FRAMES is a frame, and WINDOW isn't on that frame, just
+      return the first window on the frame.  */
+   if (FRAMEP (all_frames)
+       && !EQ (all_frames, XWINDOW (window)->frame))
+     return Fframe_first_window (all_frames);
+ 
+   if (next_p)
+     {
+       Lisp_Object list;
+ 
+       /* Find WINDOW in the list of all windows.  */
+       list = Fmemq (window, window_list ());
+ 
+       /* Scan forward from WINDOW to the end of the window list.  */
+       if (CONSP (list))
+       for (list = XCDR (list); CONSP (list); list = XCDR (list))
+         if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+           break;
+ 
+       /* Scan from the start of the window list up to WINDOW.  */
+       if (!CONSP (list))
+       for (list = Vwindow_list;
+            CONSP (list) && !EQ (XCAR (list), window);
+            list = XCDR (list))
+         if (candidate_window_p (XCAR (list), window, minibuf, all_frames))
+           break;
+ 
+       if (CONSP (list))
+       window = XCAR (list);
+     }
+   else
+     {
+       Lisp_Object candidate, list;
+ 
+       /* Scan through the list of windows for candidates.  If there are
+        candidate windows in front of WINDOW, the last one of these
+        is the one we want.  If there are candidates following WINDOW
+        in the list, again the last one of these is the one we want.  */
+       candidate = Qnil;
+       for (list = window_list (); CONSP (list); list = XCDR (list))
+       {
+         if (EQ (XCAR (list), window))
+           {
+             if (WINDOWP (candidate))
+               break;
+           }
+         else if (candidate_window_p (XCAR (list), window, minibuf,
+                                      all_frames))
+           candidate = XCAR (list);
+       }
+ 
+       if (WINDOWP (candidate))
+       window = candidate;
+     }
+ 
+   return window;
+ }
+ 
+ 
+ DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0,
+        doc: /* Return next window after WINDOW in canonical ordering of 
windows.
+ If omitted, WINDOW defaults to the selected window.
+ 
+ Optional second arg MINIBUF t means count the minibuffer window even
+ if not active.  MINIBUF nil or omitted means count the minibuffer iff
+ it is active.  MINIBUF neither t nor nil means not to count the
+ minibuffer even if it is active.
+ 
+ Several frames may share a single minibuffer; if the minibuffer
+ counts, all windows on all frames that share that minibuffer count
+ too.  Therefore, `next-window' can be used to iterate through the
+ set of windows even when the minibuffer is on another frame.  If the
+ minibuffer does not count, only windows from WINDOW's frame count.
+ 
+ Optional third arg ALL-FRAMES t means include windows on all frames.
+ ALL-FRAMES nil or omitted means cycle within the frames as specified
+ above.  ALL-FRAMES = `visible' means include windows on all visible frames.
+ ALL-FRAMES = 0 means include windows on all visible and iconified frames.
+ If ALL-FRAMES is a frame, restrict search to windows on that frame.
+ Anything else means restrict to WINDOW's frame.
+ 
+ If you use consistent values for MINIBUF and ALL-FRAMES, you can use
+ `next-window' to iterate through the entire cycle of acceptable
+ windows, eventually ending up back at the window you started with.
+ `previous-window' traverses the same cycle, in the reverse order.  */)
+      (window, minibuf, all_frames)
+      Lisp_Object window, minibuf, all_frames;
+ {
+   return next_window (window, minibuf, all_frames, 1);
+ }
+ 
+ 
+ DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0,
+        doc: /* Return the window preceding WINDOW in canonical ordering of 
windows.
+ If omitted, WINDOW defaults to the selected window.
+ 
+ Optional second arg MINIBUF t means count the minibuffer window even
+ if not active.  MINIBUF nil or omitted means count the minibuffer iff
+ it is active.  MINIBUF neither t nor nil means not to count the
+ minibuffer even if it is active.
+ 
+ Several frames may share a single minibuffer; if the minibuffer
+ counts, all windows on all frames that share that minibuffer count
+ too.  Therefore, `previous-window' can be used to iterate through
+ the set of windows even when the minibuffer is on another frame.  If
+ the minibuffer does not count, only windows from WINDOW's frame count
+ 
+ Optional third arg ALL-FRAMES t means include windows on all frames.
+ ALL-FRAMES nil or omitted means cycle within the frames as specified
+ above.  ALL-FRAMES = `visible' means include windows on all visible frames.
+ ALL-FRAMES = 0 means include windows on all visible and iconified frames.
+ If ALL-FRAMES is a frame, restrict search to windows on that frame.
+ Anything else means restrict to WINDOW's frame.
+ 
+ If you use consistent values for MINIBUF and ALL-FRAMES, you can use
+ `previous-window' to iterate through the entire cycle of acceptable
+ windows, eventually ending up back at the window you started with.
+ `next-window' traverses the same cycle, in the reverse order.  */)
+      (window, minibuf, all_frames)
+      Lisp_Object window, minibuf, all_frames;
+ {
+   return next_window (window, minibuf, all_frames, 0);
+ }
+ 
+ 
+ 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.  The optional second
+ argument ALL_FRAMES has the same meaning as in `next-window', which see.  */)
+      (arg, all_frames)
+      Lisp_Object arg, all_frames;
+ {
+   Lisp_Object window;
+   int i;
+ 
+   CHECK_NUMBER (arg);
+   window = selected_window;
+ 
+   for (i = XINT (arg); i > 0; --i)
+     window = Fnext_window (window, Qnil, all_frames);
+   for (; i < 0; ++i)
+     window = Fprevious_window (window, Qnil, all_frames);
+ 
+   Fselect_window (window, Qnil);
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("window-list", Fwindow_list, Swindow_list, 0, 3, 0,
+        doc: /* Return a list of windows on FRAME, starting with WINDOW.
+ FRAME nil or omitted means use the selected frame.
+ WINDOW nil or omitted means use the selected window.
+ MINIBUF t means include the minibuffer window, even if it isn't active.
+ MINIBUF nil or omitted means include the minibuffer window only
+ if it's active.
+ MINIBUF neither nil nor t means never include the minibuffer window.  */)
+      (frame, minibuf, window)
+      Lisp_Object frame, minibuf, window;
+ {
+   if (NILP (window))
+     window = selected_window;
+   if (NILP (frame))
+     frame = selected_frame;
+ 
+   if (!EQ (frame, XWINDOW (window)->frame))
+     error ("Window is on a different frame");
+ 
+   return window_list_1 (window, minibuf, frame);
+ }
+ 
+ 
+ /* Return a list of windows in canonical ordering.  Arguments are like
+    for `next-window'.  */
+ 
+ static Lisp_Object
+ window_list_1 (window, minibuf, all_frames)
+      Lisp_Object window, minibuf, all_frames;
+ {
+   Lisp_Object tail, list, rest;
+ 
+   decode_next_window_args (&window, &minibuf, &all_frames);
+   list = Qnil;
+ 
+   for (tail = window_list (); CONSP (tail); tail = XCDR (tail))
+     if (candidate_window_p (XCAR (tail), window, minibuf, all_frames))
+       list = Fcons (XCAR (tail), 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;
+ }
+ 
+ 
+ 
+ /* Look at all windows, performing an operation specified by TYPE
+    with argument OBJ.
+    If FRAMES is Qt, look at all frames;
+                 Qnil, look at just the selected frame;
+               Qvisible, look at visible frames;
+               a frame, just look at windows on that frame.
+    If MINI is non-zero, perform the operation on minibuffer windows too.  */
+ 
+ enum window_loop
+ {
+   WINDOW_LOOP_UNUSED,
+   GET_BUFFER_WINDOW,          /* Arg is buffer */
+   GET_LRU_WINDOW,             /* Arg is t for full-width windows only */
+   DELETE_OTHER_WINDOWS,               /* Arg is window not to delete */
+   DELETE_BUFFER_WINDOWS,      /* Arg is buffer */
+   GET_LARGEST_WINDOW,
+   UNSHOW_BUFFER,              /* Arg is buffer */
+   REDISPLAY_BUFFER_WINDOWS,   /* Arg is buffer */
+   CHECK_ALL_WINDOWS
+ };
+ 
+ static Lisp_Object
+ window_loop (type, obj, mini, frames)
+      enum window_loop type;
+      Lisp_Object obj, frames;
+      int mini;
+ {
+   Lisp_Object window, windows, best_window, frame_arg;
+   struct frame *f;
+   struct gcpro gcpro1;
+ 
+   /* If we're only looping through windows on a particular frame,
+      frame points to that frame.  If we're looping through windows
+      on all frames, frame is 0.  */
+   if (FRAMEP (frames))
+     f = XFRAME (frames);
+   else if (NILP (frames))
+     f = SELECTED_FRAME ();
+   else
+     f = NULL;
+ 
+   if (f)
+     frame_arg = Qlambda;
+   else if (XFASTINT (frames) == 0)
+     frame_arg = frames;
+   else if (EQ (frames, Qvisible))
+     frame_arg = frames;
+   else
+     frame_arg = Qt;
+ 
+   /* frame_arg is Qlambda to stick to one frame,
+      Qvisible to consider all visible frames,
+      or Qt otherwise.  */
+ 
+   /* Pick a window to start with.  */
+   if (WINDOWP (obj))
+     window = obj;
+   else if (f)
+     window = FRAME_SELECTED_WINDOW (f);
+   else
+     window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
+ 
+   windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
+   GCPRO1 (windows);
+   best_window = Qnil;
+ 
+   for (; CONSP (windows); windows = CDR (windows))
+     {
+       struct window *w;
+ 
+       window = XCAR (windows);
+       w = XWINDOW (window);
+ 
+       /* Note that we do not pay attention here to whether the frame
+        is visible, since Fwindow_list skips non-visible frames if
+        that is desired, under the control of frame_arg.  */
+       if (!MINI_WINDOW_P (w)
+         /* For UNSHOW_BUFFER, we must always consider all windows.  */
+         || type == UNSHOW_BUFFER
+         || (mini && minibuf_level > 0))
+       switch (type)
+         {
+         case GET_BUFFER_WINDOW:
+           if (EQ (w->buffer, obj)
+               /* Don't find any minibuffer window
+                  except the one that is currently in use.  */
+               && (MINI_WINDOW_P (w)
+                   ? EQ (window, minibuf_window)
+                   : 1))
+             {
+               if (NILP (best_window))
+                 best_window = window;
+               else if (EQ (window, selected_window))
+                 /* For compatibility with 20.x, prefer to return
+                    selected-window.  */
+                 best_window = window;
+             }
+           break;
+ 
+         case GET_LRU_WINDOW:
+           /* t as arg means consider only full-width windows */
+           if (!NILP (obj) && !WINDOW_FULL_WIDTH_P (w))
+             break;
+           /* Ignore dedicated windows and minibuffers.  */
+           if (MINI_WINDOW_P (w) || EQ (w->dedicated, Qt))
+             break;
+           if (NILP (best_window)
+               || (XFASTINT (XWINDOW (best_window)->use_time)
+                   > XFASTINT (w->use_time)))
+             best_window = window;
+           break;
+ 
+         case DELETE_OTHER_WINDOWS:
+           if (!EQ (window, obj))
+             Fdelete_window (window);
+           break;
+ 
+         case DELETE_BUFFER_WINDOWS:
+           if (EQ (w->buffer, obj))
+             {
+               struct frame *f = XFRAME (WINDOW_FRAME (w));
+ 
+               /* If this window is dedicated, and in a frame of its own,
+                  kill the frame.  */
+               if (EQ (window, FRAME_ROOT_WINDOW (f))
+                   && !NILP (w->dedicated)
+                   && other_visible_frames (f))
+                 {
+                   /* Skip the other windows on this frame.
+                      There might be one, the minibuffer!  */
+                   while (CONSP (XCDR (windows))
+                          && EQ (XWINDOW (XCAR (windows))->frame,
+                                 XWINDOW (XCAR (XCDR (windows)))->frame))
+                     windows = XCDR (windows);
+ 
+                   /* Now we can safely delete the frame.  */
+                   Fdelete_frame (w->frame, Qnil);
+                 }
+               else if (NILP (w->parent))
+                 {
+                   /* If we're deleting the buffer displayed in the
+                      only window on the frame, find a new buffer to
+                      display there.  */
+                   Lisp_Object buffer;
+                   buffer = Fother_buffer (obj, Qnil, w->frame);
+                   Fset_window_buffer (window, buffer, Qnil);
+                   if (EQ (window, selected_window))
+                     Fset_buffer (w->buffer);
+                 }
+               else
+                 Fdelete_window (window);
+             }
+           break;
+ 
+         case GET_LARGEST_WINDOW:
+           {
+             /* Ignore dedicated windows and minibuffers.  */
+             if (MINI_WINDOW_P (w) || EQ (w->dedicated, Qt))
+               break;
+ 
+             if (NILP (best_window))
+               best_window = window;
+             else
+               {
+                 struct window *b = XWINDOW (best_window);
+                 if (XFASTINT (w->total_lines) * XFASTINT (w->total_cols)
+                     > XFASTINT (b->total_lines) * XFASTINT (b->total_cols))
+                   best_window = window;
+               }
+           }
+           break;
+ 
+         case UNSHOW_BUFFER:
+           if (EQ (w->buffer, obj))
+             {
+               Lisp_Object buffer;
+               struct frame *f = XFRAME (w->frame);
+ 
+               /* Find another buffer to show in this window.  */
+               buffer = Fother_buffer (obj, Qnil, w->frame);
+ 
+               /* If this window is dedicated, and in a frame of its own,
+                  kill the frame.  */
+               if (EQ (window, FRAME_ROOT_WINDOW (f))
+                   && !NILP (w->dedicated)
+                   && other_visible_frames (f))
+                 {
+                   /* Skip the other windows on this frame.
+                      There might be one, the minibuffer!  */
+                   while (CONSP (XCDR (windows))
+                          && EQ (XWINDOW (XCAR (windows))->frame,
+                                 XWINDOW (XCAR (XCDR (windows)))->frame))
+                     windows = XCDR (windows);
+ 
+                   /* Now we can safely delete the frame.  */
+                   Fdelete_frame (w->frame, Qnil);
+                 }
+               else if (!NILP (w->dedicated) && !NILP (w->parent))
+                 {
+                   Lisp_Object window;
+                   XSETWINDOW (window, w);
+                   /* If this window is dedicated and not the only window
+                      in its frame, then kill it.  */
+                   Fdelete_window (window);
+                 }
+               else
+                 {
+                   /* Otherwise show a different buffer in the window.  */
+                   w->dedicated = Qnil;
+                   Fset_window_buffer (window, buffer, Qnil);
+                   if (EQ (window, selected_window))
+                     Fset_buffer (w->buffer);
+                 }
+             }
+           break;
+ 
+         case REDISPLAY_BUFFER_WINDOWS:
+           if (EQ (w->buffer, obj))
+             {
+               mark_window_display_accurate (window, 0);
+               w->update_mode_line = Qt;
+               XBUFFER (obj)->prevent_redisplay_optimizations_p = 1;
+               ++update_mode_lines;
+               best_window = window;
+             }
+           break;
+ 
+           /* Check for a window that has a killed buffer.  */
+         case CHECK_ALL_WINDOWS:
+           if (! NILP (w->buffer)
+               && NILP (XBUFFER (w->buffer)->name))
+             abort ();
+           break;
+ 
+         case WINDOW_LOOP_UNUSED:
+           break;
+         }
+     }
+ 
+   UNGCPRO;
+   return best_window;
+ }
+ 
+ /* Used for debugging.  Abort if any window has a dead buffer.  */
+ 
+ void
+ check_all_windows ()
+ {
+   window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
+ }
+ 
+ DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
+        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.
+ 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.
+ If FRAME is nil, search only the selected frame.
+ If FRAME is a frame, search only that frame.  */)
+      (frame)
+      Lisp_Object frame;
+ {
+   register Lisp_Object w;
+   /* First try for a window that is full-width */
+   w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
+   if (!NILP (w) && !EQ (w, selected_window))
+     return w;
+   /* If none of them, try the rest */
+   return window_loop (GET_LRU_WINDOW, Qnil, 0, 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.
+ 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.
+ If FRAME is nil, search only the selected frame.
+ If FRAME is a frame, search only that frame.  */)
+      (frame)
+      Lisp_Object frame;
+ {
+   return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
+                     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.
+ If FRAME is nil, search only the selected frame.
+ If FRAME is a frame, search only that frame.  */)
+      (buffer, frame)
+      Lisp_Object buffer, frame;
+ {
+   buffer = Fget_buffer (buffer);
+   if (BUFFERP (buffer))
+     return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame);
+   else
+     return Qnil;
+ }
+ 
+ DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
+        0, 1, "",
+        doc: /* Make WINDOW (or the selected window) fill its frame.
+ Only the frame WINDOW is on is affected.
+ This function tries to reduce display jumps
+ by keeping the text previously visible in WINDOW
+ in the same place on the frame.  Doing this depends on
+ the value of (window-start WINDOW), so if calling this function
+ in a program gives strange scrolling, make sure the window-start
+ value is reasonable when this function is called.  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w;
+   int startpos;
+   int top, new_top;
+ 
+   if (NILP (window))
+     window = selected_window;
+   else
+     CHECK_LIVE_WINDOW (window);
+   w = XWINDOW (window);
+ 
+   startpos = marker_position (w->start);
+   top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME 
(w)));
+ 
+   if (MINI_WINDOW_P (w) && top > 0)
+     error ("Can't expand minibuffer to full frame");
+ 
+   window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
+ 
+   /* Try to minimize scrolling, by setting the window start to the point
+      will cause the text at the old window start to be at the same place
+      on the frame.  But don't try to do this if the window start is
+      outside the visible portion (as might happen when the display is
+      not current, due to typeahead).  */
+   new_top = WINDOW_TOP_EDGE_LINE (w) - FRAME_TOP_MARGIN (XFRAME (WINDOW_FRAME 
(w)));
+   if (new_top != top
+       && startpos >= BUF_BEGV (XBUFFER (w->buffer))
+       && startpos <= BUF_ZV (XBUFFER (w->buffer)))
+     {
+       struct position pos;
+       struct buffer *obuf = current_buffer;
+ 
+       Fset_buffer (w->buffer);
+       /* This computation used to temporarily move point, but that can
+        have unwanted side effects due to text properties.  */
+       pos = *vmotion (startpos, -top, w);
+ 
+       set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+       w->window_end_valid = Qnil;
+       w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+                              || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
+                             : Qnil);
+       /* We need to do this, so that the window-scroll-functions
+        get called.  */
+       w->optional_new_start = Qt;
+ 
+       set_buffer_internal (obuf);
+     }
+ 
+   return Qnil;
+ }
+ 
+ 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.
+ If FRAME is nil, search all frames.
+ If FRAME is t, search only the selected frame.
+ If FRAME is a frame, search only that frame.  */)
+      (buffer, frame)
+      Lisp_Object buffer, frame;
+ {
+   /* FRAME uses t and nil to mean the opposite of what window_loop
+      expects.  */
+   if (NILP (frame))
+     frame = Qt;
+   else if (EQ (frame, Qt))
+     frame = Qnil;
+ 
+   if (!NILP (buffer))
+     {
+       buffer = Fget_buffer (buffer);
+       CHECK_BUFFER (buffer);
+       window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame);
+     }
+ 
+   return Qnil;
+ }
+ 
+ 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.
+ BUFFER may be a buffer or the name of an existing buffer.  */)
+      (buffer)
+      Lisp_Object buffer;
+ {
+   if (!NILP (buffer))
+     {
+       buffer = Fget_buffer (buffer);
+       CHECK_BUFFER (buffer);
+       window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
+     }
+   return Qnil;
+ }
+ 
+ /* Replace BUFFER with some other buffer in all windows
+    of all frames, even those on other keyboards.  */
+ 
+ void
+ replace_buffer_in_all_windows (buffer)
+      Lisp_Object buffer;
+ {
+ #ifdef MULTI_KBOARD
+   Lisp_Object tail, frame;
+ 
+   /* A single call to window_loop won't do the job
+      because it only considers frames on the current keyboard.
+      So loop manually over frames, and handle each one.  */
+   FOR_EACH_FRAME (tail, frame)
+     window_loop (UNSHOW_BUFFER, buffer, 1, frame);
+ #else
+   window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
+ #endif
+ }
+ 
+ /* Set the height of WINDOW and all its inferiors.  */
+ 
+ /* The smallest acceptable dimensions for a window.  Anything smaller
+    might crash Emacs.  */
+ 
+ #define MIN_SAFE_WINDOW_WIDTH  (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.  */
+ 
+ static void
+ check_min_window_sizes ()
+ {
+   /* Smaller values might permit a crash.  */
+   if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
+     window_min_width = MIN_SAFE_WINDOW_WIDTH;
+   if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
+     window_min_height = MIN_SAFE_WINDOW_HEIGHT;
+ }
+ 
+ /* If *ROWS or *COLS are too small a size for FRAME, set them to the
+    minimum allowable size.  */
+ 
+ void
+ check_frame_size (frame, rows, cols)
+      FRAME_PTR frame;
+      int *rows, *cols;
+ {
+   /* For height, we have to see:
+      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);
+ 
+   if (*rows < min_height)
+     *rows = min_height;
+   if (*cols  < MIN_SAFE_WINDOW_WIDTH)
+     *cols = MIN_SAFE_WINDOW_WIDTH;
+ }
+ 
+ 
+ /* Value is non-zero if window W is fixed-size.  WIDTH_P non-zero means
+    check if W's width can be changed, otherwise check W's height.
+    CHECK_SIBLINGS_P non-zero means check resizablity of WINDOW's
+    siblings, too.  If none of the siblings is resizable, WINDOW isn't
+    either.  */
+ 
+ static int
+ window_fixed_size_p (w, width_p, check_siblings_p)
+      struct window *w;
+      int width_p, check_siblings_p;
+ {
+   int fixed_p;
+   struct window *c;
+ 
+   if (!NILP (w->hchild))
+     {
+       c = XWINDOW (w->hchild);
+ 
+       if (width_p)
+       {
+         /* A horiz. combination is fixed-width if all of if its
+            children are.  */
+         while (c && window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c == NULL;
+       }
+       else
+       {
+         /* A horiz. combination is fixed-height if one of if its
+            children is.  */
+         while (c && !window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c != NULL;
+       }
+     }
+   else if (!NILP (w->vchild))
+     {
+       c = XWINDOW (w->vchild);
+ 
+       if (width_p)
+       {
+         /* A vert. combination is fixed-width if one of if its
+            children is.  */
+         while (c && !window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c != NULL;
+       }
+       else
+       {
+         /* A vert. combination is fixed-height if all of if its
+            children are.  */
+         while (c && window_fixed_size_p (c, width_p, 0))
+           c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+         fixed_p = c == NULL;
+       }
+     }
+   else if (BUFFERP (w->buffer))
+     {
+       if (w->height_fixed_p && !width_p)
+       fixed_p = 1;
+       else
+       {
+         struct buffer *old = current_buffer;
+         Lisp_Object val;
+ 
+         current_buffer = XBUFFER (w->buffer);
+         val = find_symbol_value (Qwindow_size_fixed);
+         current_buffer = old;
+ 
+         fixed_p = 0;
+         if (!EQ (val, Qunbound))
+           {
+             fixed_p = !NILP (val);
+ 
+             if (fixed_p
+                 && ((EQ (val, Qheight) && width_p)
+                     || (EQ (val, Qwidth) && !width_p)))
+               fixed_p = 0;
+           }
+       }
+ 
+       /* Can't tell if this one is resizable without looking at
+        siblings.  If all siblings are fixed-size this one is too.  */
+       if (!fixed_p && check_siblings_p && WINDOWP (w->parent))
+       {
+         Lisp_Object child;
+ 
+         for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
+           if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+             break;
+ 
+         if (NILP (child))
+           for (child = w->next; !NILP (child); child = XWINDOW (child)->next)
+             if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
+               break;
+ 
+         if (NILP (child))
+           fixed_p = 1;
+       }
+     }
+   else
+     fixed_p = 1;
+ 
+   return fixed_p;
+ }
+ 
+ 
+ /* Return the minimum size of window W, not taking fixed-width windows
+    into account.  WIDTH_P non-zero means return the minimum width,
+    otherwise return the minimum height.  If W is a combination window,
+    compute the minimum size from the minimum sizes of W's children.  */
+ 
+ static int
+ window_min_size_1 (w, width_p)
+      struct window *w;
+      int width_p;
+ {
+   struct window *c;
+   int size;
+ 
+   if (!NILP (w->hchild))
+     {
+       c = XWINDOW (w->hchild);
+       size = 0;
+ 
+       if (width_p)
+       {
+         /* The min width of a horizontal combination is
+            the sum of the min widths of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+       else
+       {
+         /* The min height a horizontal combination equals
+            the maximum of all min height of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+     }
+   else if (!NILP (w->vchild))
+     {
+       c = XWINDOW (w->vchild);
+       size = 0;
+ 
+       if (width_p)
+       {
+         /* The min width of a vertical combination is
+            the maximum of the min widths of its children.  */
+         while (c)
+           {
+             int min_size = window_min_size_1 (c, width_p);
+             size = max (min_size, size);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+       else
+       {
+         /* The min height of a vertical combination equals
+            the sum of the min height of its children.  */
+         while (c)
+           {
+             size += window_min_size_1 (c, width_p);
+             c = WINDOWP (c->next) ? XWINDOW (c->next) : NULL;
+           }
+       }
+     }
+   else
+     {
+       if (width_p)
+       size = window_min_width;
+       else
+       {
+         if (MINI_WINDOW_P (w)
+             || (!WINDOW_WANTS_MODELINE_P (w)
+                 && !WINDOW_WANTS_HEADER_LINE_P (w)))
+           size = 1;
+         else
+           size = window_min_height;
+       }
+     }
+ 
+   return size;
+ }
+ 
+ 
+ /* Return the minimum size of window W, taking fixed-size windows into
+    account.  WIDTH_P non-zero means return the minimum width,
+    otherwise return the minimum height.  IGNORE_FIXED_P non-zero means
+    ignore if W is fixed-size.  Set *FIXED to 1 if W is fixed-size
+    unless FIXED is null.  */
+ 
+ static int
+ window_min_size (w, width_p, ignore_fixed_p, fixed)
+      struct window *w;
+      int width_p, ignore_fixed_p, *fixed;
+ {
+   int size, fixed_p;
+ 
+   if (ignore_fixed_p)
+     fixed_p = 0;
+   else
+     fixed_p = window_fixed_size_p (w, width_p, 1);
+ 
+   if (fixed)
+     *fixed = fixed_p;
+ 
+   if (fixed_p)
+     size = width_p ? XFASTINT (w->total_cols) : XFASTINT (w->total_lines);
+   else
+     size = window_min_size_1 (w, width_p);
+ 
+   return size;
+ }
+ 
+ 
+ /* Adjust the margins of window W if text area is too small.
+    Return 1 if window width is ok after adjustment; 0 if window
+    is still too narrow.  */
+ 
+ static int
+ adjust_window_margins (w)
+      struct window *w;
+ {
+   int box_cols = (WINDOW_TOTAL_COLS (w)
+                 - WINDOW_FRINGE_COLS (w)
+                 - WINDOW_SCROLL_BAR_COLS (w));
+   int margin_cols = (WINDOW_LEFT_MARGIN_COLS (w)
+                    + WINDOW_RIGHT_MARGIN_COLS (w));
+ 
+   if (box_cols - margin_cols >= MIN_SAFE_WINDOW_WIDTH)
+     return 1;
+ 
+   if (margin_cols < 0 || box_cols < MIN_SAFE_WINDOW_WIDTH)
+     return 0;
+ 
+   /* Window's text area is too narrow, but reducing the window
+      margins will fix that.  */
+   margin_cols = box_cols - MIN_SAFE_WINDOW_WIDTH;
+   if (WINDOW_RIGHT_MARGIN_COLS (w) > 0)
+     {
+       if (WINDOW_LEFT_MARGIN_COLS (w) > 0)
+       w->left_margin_cols = w->right_margin_cols
+         = make_number (margin_cols/2);
+       else
+       w->right_margin_cols = make_number (margin_cols);
+     }
+   else
+     w->left_margin_cols = make_number (margin_cols);
+   return 1;
+ }
+ 
+ /* Calculate new sizes for windows in the list FORWARD when the window size
+    goes from TOTAL to SIZE.  TOTAL must be greater than SIZE.
+    The number of windows in FORWARD is NCHILDREN, and the number that
+    can shrink is SHRINKABLE.
+    The minimum size a window can have is MIN_SIZE.
+    If we are shrinking fixed windows, RESIZE_FIXED_P is non-zero.
+    If we are shrinking columns, WIDTH_P is non-zero, otherwise we are
+    shrinking rows.
+ 
+    This function returns an allocated array of new sizes that the caller
+    must free.  The size -1 means the window is fixed and RESIZE_FIXED_P
+    is zero.  Array index 0 refers to the first window in FORWARD, 1 to
+    the second, and so on.
+ 
+    This function tries to keep windows at least at the minimum size
+    and resize other windows before it resizes any window to zero (i.e.
+    delete that window).
+ 
+    Windows are resized proportional to their size, so bigger windows
+    shrink more than smaller windows.  */
+ static int *
+ shrink_windows (total, size, nchildren, shrinkable,
+                 min_size, resize_fixed_p, forward, width_p)
+      int total, size, nchildren, shrinkable, min_size;
+      int resize_fixed_p, width_p;
+      Lisp_Object forward;
+ {
+   int available_resize = 0;
+   int *new_sizes;
+   struct window *c;
+   Lisp_Object child;
+   int smallest = total;
+   int total_removed = 0;
+   int total_shrink = total - size;
+   int i;
+ 
+   new_sizes = xmalloc (sizeof (*new_sizes) * nchildren);
+ 
+   for (i = 0, child = forward; !NILP (child); child = c->next, ++i)
+     {
+       int child_size;
+ 
+       c = XWINDOW (child);
+       child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
+ 
+       if (! resize_fixed_p && window_fixed_size_p (c, width_p, 0))
+         new_sizes[i] = -1;
+       else
+         {
+           new_sizes[i] = child_size;
+           if (child_size > min_size)
+             available_resize += child_size - min_size;
+         }
+     }
+   /* We might need to shrink some windows to zero.  Find the smallest
+      windows and set them to 0 until we can fulfil the new size.  */
+ 
+   while (shrinkable > 1 && size + available_resize < total)
+     {
+       for (i = 0; i < nchildren; ++i)
+         if (new_sizes[i] > 0 && smallest > new_sizes[i])
+           smallest = new_sizes[i];
+ 
+       for (i = 0; i < nchildren; ++i)
+         if (new_sizes[i] == smallest)
+           {
+             /* Resize this window down to zero.  */
+             new_sizes[i] = 0;
+             if (smallest > min_size)
+               available_resize -= smallest - min_size;
+             available_resize += smallest;
+             --shrinkable;
+             total_removed += smallest;
+ 
+             /* Out of for, just remove one window at the time and
+                check again if we have enough space.  */
+             break;
+           }
+     }
+ 
+   /* Now, calculate the new sizes.  Try to shrink each window
+      proportional to its size.  */
+   for (i = 0; i < nchildren; ++i)
+     {
+       if (new_sizes[i] > min_size)
+         {
+           int to_shrink = total_shrink*new_sizes[i]/total;
+           if (new_sizes[i] - to_shrink < min_size)
+             to_shrink = new_sizes[i] - min_size;
+           new_sizes[i] -= to_shrink;
+           total_removed += to_shrink;
+         }
+     }
+ 
+   /* Any reminder due to rounding, we just subtract from windows
+      that are left and still can be shrunk.  */
+   while (total_shrink > total_removed)
+     {
+       for (i = 0; i < nchildren; ++i)
+         if (new_sizes[i] > min_size)
+           {
+             --new_sizes[i];
+             ++total_removed;
+ 
+             /* Out of for, just shrink one window at the time and
+                check again if we have enough space.  */
+             break;
+           }
+     }
+ 
+   return new_sizes;
+ }
+ 
+ /* Set WINDOW's height or width to SIZE.  WIDTH_P non-zero means set
+    WINDOW's width.  Resize WINDOW's children, if any, so that they
+    keep their proportionate size relative to WINDOW.  Propagate
+    WINDOW's top or left edge position to children.  Delete windows
+    that become too small unless NODELETE_P is non-zero.
+ 
+    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)
+      Lisp_Object window;
+      int size, width_p, nodelete_p;
+ {
+   struct window *w = XWINDOW (window);
+   struct window *c;
+   Lisp_Object child, *forward, *sideward;
+   int old_size, min_size, safe_min_size;
+ 
+   /* We test nodelete_p != 2 and nodelete_p != 1 below, so it
+      seems like it's too soon to do this here.  ++KFS.  */
+   if (nodelete_p == 2)
+     nodelete_p = 0;
+ 
+   check_min_window_sizes ();
+   size = max (0, size);
+ 
+   /* If the window has been "too small" at one point,
+      don't delete it for being "too small" in the future.
+      Preserve it as long as that is at all possible.  */
+   if (width_p)
+     {
+       old_size = WINDOW_TOTAL_COLS (w);
+       min_size = window_min_width;
+       /* Ensure that there is room for the scroll bar and fringes!
+          We may reduce display margins though.  */
+       safe_min_size = (MIN_SAFE_WINDOW_WIDTH
+                      + WINDOW_FRINGE_COLS (w)
+                      + WINDOW_SCROLL_BAR_COLS (w));
+     }
+   else
+     {
+       old_size = XINT (w->total_lines);
+       min_size = window_min_height;
+       safe_min_size = MIN_SAFE_WINDOW_HEIGHT;
+     }
+ 
+   if (old_size < min_size && nodelete_p != 2)
+     w->too_small_ok = Qt;
+ 
+   /* Maybe delete WINDOW if it's too small.  */
+   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;
+       if (min_size < safe_min_size)
+       min_size = safe_min_size;
+       if (size < min_size)
+       {
+         delete_window (window);
+         return;
+       }
+     }
+ 
+   /* Set redisplay hints.  */
+   w->last_modified = make_number (0);
+   w->last_overlay_modified = make_number (0);
+   windows_or_buffers_changed++;
+   FRAME_WINDOW_SIZES_CHANGED (XFRAME (w->frame)) = 1;
+ 
+   if (width_p)
+     {
+       sideward = &w->vchild;
+       forward = &w->hchild;
+       w->total_cols = make_number (size);
+       adjust_window_margins (w);
+     }
+   else
+     {
+       sideward = &w->hchild;
+       forward = &w->vchild;
+       w->total_lines = make_number (size);
+       w->orig_total_lines = Qnil;
+     }
+ 
+   if (!NILP (*sideward))
+     {
+       for (child = *sideward; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         if (width_p)
+           c->left_col = w->left_col;
+         else
+           c->top_line = w->top_line;
+         size_window (child, size, width_p, nodelete_p);
+       }
+     }
+   else if (!NILP (*forward))
+     {
+       int fixed_size, each, extra, n;
+       int resize_fixed_p, nfixed;
+       int last_pos, first_pos, nchildren, total;
+       int *new_sizes = NULL;
+ 
+       /* Determine the fixed-size portion of the this window, and the
+        number of child windows.  */
+       fixed_size = nchildren = nfixed = total = 0;
+       for (child = *forward; !NILP (child); child = c->next, ++nchildren)
+       {
+         int child_size;
+ 
+         c = XWINDOW (child);
+         child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
+         total += child_size;
+ 
+         if (window_fixed_size_p (c, width_p, 0))
+           {
+             fixed_size += child_size;
+             ++nfixed;
+           }
+       }
+ 
+       /* If the new size is smaller than fixed_size, or if there
+        aren't any resizable windows, allow resizing fixed-size
+        windows.  */
+       resize_fixed_p = nfixed == nchildren || size < fixed_size;
+ 
+       /* Compute how many lines/columns to add/remove to each child.  The
+        value of extra takes care of rounding errors.  */
+       n = resize_fixed_p ? nchildren : nchildren - nfixed;
+       if (size < total && n > 1)
+         new_sizes = shrink_windows (total, size, nchildren, n, min_size,
+                                     resize_fixed_p, *forward, width_p);
+       else
+         {
+           each = (size - total) / n;
+           extra = (size - total) - n * each;
+         }
+ 
+       /* Compute new children heights and edge positions.  */
+       first_pos = width_p ? XINT (w->left_col) : XINT (w->top_line);
+       last_pos = first_pos;
+       for (n = 0, child = *forward; !NILP (child); child = c->next, ++n)
+       {
+         int new_size, old_size;
+ 
+         c = XWINDOW (child);
+         old_size = width_p ? XFASTINT (c->total_cols) : XFASTINT 
(c->total_lines);
+         new_size = old_size;
+ 
+         /* The top or left edge position of this child equals the
+            bottom or right edge of its predecessor.  */
+         if (width_p)
+           c->left_col = make_number (last_pos);
+         else
+           c->top_line = make_number (last_pos);
+ 
+         /* If this child can be resized, do it.  */
+         if (resize_fixed_p || !window_fixed_size_p (c, width_p, 0))
+           {
+             new_size = new_sizes ? new_sizes[n] : old_size + each + extra;
+             extra = 0;
+           }
+ 
+         /* Set new height.  Note that size_window also propagates
+            edge positions to children, so it's not a no-op if we
+            didn't change the child's size.  */
+         size_window (child, new_size, width_p, 1);
+ 
+         /* Remember the bottom/right edge position of this child; it
+            will be used to set the top/left edge of the next child.  */
+           last_pos += new_size;
+       }
+ 
+       if (new_sizes) xfree (new_sizes);
+ 
+       /* We should have covered the parent exactly with child windows.  */
+       xassert (size == last_pos - first_pos);
+ 
+       /* Now delete any children that became too small.  */
+       if (!nodelete_p)
+       for (child = *forward; !NILP (child); child = c->next)
+         {
+           int child_size;
+           c = XWINDOW (child);
+           child_size = width_p ? XINT (c->total_cols) : XINT (c->total_lines);
+           size_window (child, child_size, width_p, 2);
+         }
+     }
+ }
+ 
+ /* Set WINDOW's height to HEIGHT, and recursively change the height of
+    WINDOW's children.  NODELETE non-zero means don't delete windows
+    that become too small in the process.  (The caller should check
+    later and do so if appropriate.)  */
+ 
+ void
+ set_window_height (window, height, nodelete)
+      Lisp_Object window;
+      int height;
+      int nodelete;
+ {
+   size_window (window, height, 0, nodelete);
+ }
+ 
+ 
+ /* Set WINDOW's width to WIDTH, and recursively change the width of
+    WINDOW's children.  NODELETE non-zero means don't delete windows
+    that become too small in the process.  (The caller should check
+    later and do so if appropriate.)  */
+ 
+ void
+ set_window_width (window, width, nodelete)
+      Lisp_Object window;
+      int width;
+      int nodelete;
+ {
+   size_window (window, width, 1, nodelete);
+ }
+ 
+ /* Change window heights in windows rooted in WINDOW by N lines.  */
+ 
+ void
+ change_window_heights (window, n)
+      Lisp_Object window;
+      int n;
+ {
+   struct window *w = XWINDOW (window);
+ 
+   XSETFASTINT (w->top_line, XFASTINT (w->top_line) + n);
+   XSETFASTINT (w->total_lines, XFASTINT (w->total_lines) - n);
+ 
+   if (INTEGERP (w->orig_top_line))
+     XSETFASTINT (w->orig_top_line, XFASTINT (w->orig_top_line) + n);
+   if (INTEGERP (w->orig_total_lines))
+     XSETFASTINT (w->orig_total_lines, XFASTINT (w->orig_total_lines) - n);
+ 
+   /* Handle just the top child in a vertical split.  */
+   if (!NILP (w->vchild))
+     change_window_heights (w->vchild, n);
+ 
+   /* Adjust all children in a horizontal split.  */
+   for (window = w->hchild; !NILP (window); window = w->next)
+     {
+       w = XWINDOW (window);
+       change_window_heights (window, n);
+     }
+ }
+ 
+ 
+ int window_select_count;
+ 
+ Lisp_Object
+ Fset_window_buffer_unwind (obuf)
+      Lisp_Object obuf;
+ {
+   Fset_buffer (obuf);
+   return Qnil;
+ }
+ 
+ EXFUN (Fset_window_fringes, 4);
+ EXFUN (Fset_window_scroll_bars, 4);
+ 
+ /* Make WINDOW display BUFFER as its contents.  RUN_HOOKS_P non-zero
+    means it's allowed to run hooks.  See make_frame for a case where
+    it's not allowed.  KEEP_MARGINS_P non-zero means that the current
+    margins, fringes, and scroll-bar settings of the window are not
+    reset from the buffer's local settings.  */
+ 
+ void
+ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
+      Lisp_Object window, buffer;
+      int run_hooks_p, keep_margins_p;
+ {
+   struct window *w = XWINDOW (window);
+   struct buffer *b = XBUFFER (buffer);
+   int count = SPECPDL_INDEX ();
+ 
+   w->buffer = buffer;
+ 
+   if (EQ (window, selected_window))
+     b->last_selected_window = window;
+ 
+   /* Update time stamps of buffer display.  */
+   if (INTEGERP (b->display_count))
+     XSETINT (b->display_count, XINT (b->display_count) + 1);
+   b->display_time = Fcurrent_time ();
+ 
+   XSETFASTINT (w->window_end_pos, 0);
+   XSETFASTINT (w->window_end_vpos, 0);
+   bzero (&w->last_cursor, sizeof w->last_cursor);
+   w->window_end_valid = Qnil;
+   w->hscroll = w->min_hscroll = make_number (0);
+   w->vscroll = 0;
+   set_marker_both (w->pointm, buffer, BUF_PT (b), BUF_PT_BYTE (b));
+   set_marker_restricted (w->start,
+                        make_number (b->last_window_start),
+                        buffer);
+   w->start_at_line_beg = Qnil;
+   w->force_start = Qnil;
+   XSETFASTINT (w->last_modified, 0);
+   XSETFASTINT (w->last_overlay_modified, 0);
+   windows_or_buffers_changed++;
+ 
+   /* We must select BUFFER for running the window-scroll-functions.
+      If WINDOW is selected, switch permanently.
+      Otherwise, switch but go back to the ambient buffer afterward.  */
+   if (EQ (window, selected_window))
+     Fset_buffer (buffer);
+   /* We can't check ! NILP (Vwindow_scroll_functions) here
+      because that might itself be a local variable.  */
+   else if (window_initialized)
+     {
+       record_unwind_protect (Fset_window_buffer_unwind, Fcurrent_buffer ());
+       Fset_buffer (buffer);
+     }
+ 
+   if (!keep_margins_p)
+     {
+       /* Set left and right marginal area width etc. from buffer.  */
+ 
+       /* This may call adjust_window_margins three times, so
+        temporarily disable window margins.  */
+       Lisp_Object save_left = w->left_margin_cols;
+       Lisp_Object save_right = w->right_margin_cols;
+ 
+       w->left_margin_cols = w->right_margin_cols = Qnil;
+ 
+       Fset_window_fringes (window,
+                          b->left_fringe_width, b->right_fringe_width,
+                          b->fringes_outside_margins);
+ 
+       Fset_window_scroll_bars (window,
+                              b->scroll_bar_width,
+                              b->vertical_scroll_bar_type, Qnil);
+ 
+       w->left_margin_cols = save_left;
+       w->right_margin_cols = save_right;
+ 
+       Fset_window_margins (window,
+                          b->left_margin_cols, b->right_margin_cols);
+     }
+ 
+   if (run_hooks_p)
+     {
+       if (! NILP (Vwindow_scroll_functions))
+       run_hook_with_args_2 (Qwindow_scroll_functions, window,
+                             Fmarker_position (w->start));
+ 
+       if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+     }
+ 
+   unbind_to (count, Qnil);
+ }
+ 
+ 
+ DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 3, 0,
+        doc: /* Make WINDOW display BUFFER as its contents.
+ 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.  */)
+      (window, buffer, keep_margins)
+      register Lisp_Object window, buffer, keep_margins;
+ {
+   register Lisp_Object tem;
+   register struct window *w = decode_window (window);
+ 
+   XSETWINDOW (window, w);
+   buffer = Fget_buffer (buffer);
+   CHECK_BUFFER (buffer);
+ 
+   if (NILP (XBUFFER (buffer)->name))
+     error ("Attempt to display deleted buffer");
+ 
+   tem = w->buffer;
+   if (NILP (tem))
+     error ("Window is deleted");
+   else if (! EQ (tem, Qt))    /* w->buffer is t when the window
+                                  is first being set up.  */
+     {
+       if (!NILP (w->dedicated) && !EQ (tem, buffer))
+       error ("Window is dedicated to `%s'",
+              SDATA (XBUFFER (tem)->name));
+ 
+       unshow_buffer (w);
+     }
+ 
+   set_window_buffer (window, buffer, 1, !NILP (keep_margins));
+   return Qnil;
+ }
+ 
+ /* Note that selected_window can be nil
+    when this is called from Fset_window_configuration.  */
+ 
+ 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, 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.
+ 
+ Note that the main editor command loop
+ selects the buffer of the selected window before each command.  */)
+      (window, norecord)
+      register Lisp_Object window, norecord;
+ {
+   register struct window *w;
+   register struct window *ow;
+   struct frame *sf;
+ 
+   CHECK_LIVE_WINDOW (window);
+ 
+   w = XWINDOW (window);
+   w->frozen_window_start_p = 0;
+ 
+   XSETFASTINT (w->use_time, ++window_select_count);
+   if (EQ (window, selected_window))
+     return window;
+ 
+   if (!NILP (selected_window))
+     {
+       ow = XWINDOW (selected_window);
+       if (! NILP (ow->buffer))
+       set_marker_both (ow->pointm, ow->buffer,
+                        BUF_PT (XBUFFER (ow->buffer)),
+                        BUF_PT_BYTE (XBUFFER (ow->buffer)));
+     }
+ 
+   selected_window = window;
+   sf = SELECTED_FRAME ();
+   if (XFRAME (WINDOW_FRAME (w)) != sf)
+     {
+       XFRAME (WINDOW_FRAME (w))->selected_window = window;
+       /* Use this rather than Fhandle_switch_frame
+        so that FRAME_FOCUS_FRAME is moved appropriately as we
+        move around in the state where a minibuffer in a separate
+        frame is active.  */
+       Fselect_frame (WINDOW_FRAME (w), Qnil);
+     }
+   else
+     sf->selected_window = window;
+ 
+   if (NILP (norecord))
+     record_buffer (w->buffer);
+   Fset_buffer (w->buffer);
+ 
+   XBUFFER (w->buffer)->last_selected_window = window;
+ 
+   /* Go to the point recorded in the window.
+      This is important when the buffer is in more
+      than one window.  It also matters when
+      redisplay_window has altered point after scrolling,
+      because it makes the change only in the window.  */
+   {
+     register int new_point = marker_position (w->pointm);
+     if (new_point < BEGV)
+       SET_PT (BEGV);
+     else if (new_point > ZV)
+       SET_PT (ZV);
+     else
+       SET_PT (new_point);
+   }
+ 
+   windows_or_buffers_changed++;
+   return window;
+ }
+ 
+ static Lisp_Object
+ select_window_norecord (window)
+      Lisp_Object window;
+ {
+   return Fselect_window (window, Qt);
+ }
+ 
+ /* Deiconify the frame containing the window WINDOW,
+    unless it is the selected frame;
+    then return WINDOW.
+ 
+    The reason for the exception for the selected frame
+    is that it seems better not to change the selected frames visibility
+    merely because of displaying a different buffer in it.
+    The deiconification is useful when a buffer gets shown in
+    another frame that you were not using lately.  */
+ 
+ static Lisp_Object
+ display_buffer_1 (window)
+      Lisp_Object window;
+ {
+   Lisp_Object frame = XWINDOW (window)->frame;
+   FRAME_PTR f = XFRAME (frame);
+ 
+   FRAME_SAMPLE_VISIBILITY (f);
+ 
+   if (EQ (frame, selected_frame))
+     ; /* Assume the selected frame is already visible enough.  */
+   else if (minibuf_level > 0
+          && MINI_WINDOW_P (XWINDOW (selected_window))
+          && WINDOW_LIVE_P (minibuf_selected_window)
+          && EQ (frame, WINDOW_FRAME (XWINDOW (minibuf_selected_window))))
+     ; /* Assume the frame from which we invoked the minibuffer is visible.  */
+   else
+     {
+       if (FRAME_ICONIFIED_P (f))
+       Fmake_frame_visible (frame);
+       else if (FRAME_VISIBLE_P (f))
+       Fraise_frame (frame);
+     }
+ 
+   return 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'.  */)
+      (buffer_name)
+      Lisp_Object buffer_name;
+ {
+   Lisp_Object tem;
+ 
+   CHECK_STRING (buffer_name);
+ 
+   tem = Fmember (buffer_name, Vspecial_display_buffer_names);
+   if (!NILP (tem))
+     return Qt;
+ 
+   tem = Fassoc (buffer_name, Vspecial_display_buffer_names);
+   if (!NILP (tem))
+     return XCDR (tem);
+ 
+   for (tem = Vspecial_display_regexps; CONSP (tem); tem = XCDR (tem))
+     {
+       Lisp_Object car = XCAR (tem);
+       if (STRINGP (car)
+         && fast_string_match (car, buffer_name) >= 0)
+       return Qt;
+       else if (CONSP (car)
+              && STRINGP (XCAR (car))
+              && fast_string_match (XCAR (car), buffer_name) >= 0)
+       return XCDR (car);
+     }
+   return Qnil;
+ }
+ 
+ DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
+        doc: /* Returns non-nil if a new buffer named BUFFER-NAME would use 
the same window.
+ See `same-window-buffer-names' and `same-window-regexps'.  */)
+      (buffer_name)
+      Lisp_Object buffer_name;
+ {
+   Lisp_Object tem;
+ 
+   CHECK_STRING (buffer_name);
+ 
+   tem = Fmember (buffer_name, Vsame_window_buffer_names);
+   if (!NILP (tem))
+     return Qt;
+ 
+   tem = Fassoc (buffer_name, Vsame_window_buffer_names);
+   if (!NILP (tem))
+     return Qt;
+ 
+   for (tem = Vsame_window_regexps; CONSP (tem); tem = XCDR (tem))
+     {
+       Lisp_Object car = XCAR (tem);
+       if (STRINGP (car)
+         && fast_string_match (car, buffer_name) >= 0)
+       return Qt;
+       else if (CONSP (car)
+              && STRINGP (XCAR (car))
+              && fast_string_match (XCAR (car), buffer_name) >= 0)
+       return Qt;
+     }
+   return Qnil;
+ }
+ 
+ /* Use B so the default is (other-buffer).  */
+ 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 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).
+ If `pop-up-frames' is non-nil, make a new frame if no window shows BUFFER.
+ 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 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.
+ If FRAME is t, search all frames.
+ If FRAME is a frame, search only that frame.
+ If FRAME is nil, search only the selected frame
+  (actually the last nonminibuffer 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.  */)
+      (buffer, not_this_window, frame)
+      register Lisp_Object buffer, not_this_window, frame;
+ {
+   register Lisp_Object window, tem, swp;
+   struct frame *f;
+ 
+   swp = Qnil;
+   buffer = Fget_buffer (buffer);
+   CHECK_BUFFER (buffer);
+ 
+   if (!NILP (Vdisplay_buffer_function))
+     return call2 (Vdisplay_buffer_function, buffer, not_this_window);
+ 
+   if (NILP (not_this_window)
+       && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer))
+     return display_buffer_1 (selected_window);
+ 
+   /* See if the user has specified this buffer should appear
+      in the selected window.  */
+   if (NILP (not_this_window))
+     {
+       swp = Fsame_window_p (XBUFFER (buffer)->name);
+       if (!NILP (swp) && !no_switch_window (selected_window))
+       {
+         Fswitch_to_buffer (buffer, Qnil);
+         return display_buffer_1 (selected_window);
+       }
+     }
+ 
+   /* If the user wants pop-up-frames or display-buffer-reuse-frames,
+      look for a window showing BUFFER on any visible or iconified frame.
+      Otherwise search only the current frame.  */
+   if (! NILP (frame))
+     tem = frame;
+   else if (pop_up_frames
+          || display_buffer_reuse_frames
+          || last_nonminibuf_frame == 0)
+     XSETFASTINT (tem, 0);
+   else
+     XSETFRAME (tem, last_nonminibuf_frame);
+ 
+   window = Fget_buffer_window (buffer, tem);
+   if (!NILP (window)
+       && (NILP (not_this_window) || !EQ (window, selected_window)))
+     return display_buffer_1 (window);
+ 
+   /* Certain buffer names get special handling.  */
+   if (!NILP (Vspecial_display_function) && NILP (swp))
+     {
+       tem = Fspecial_display_p (XBUFFER (buffer)->name);
+       if (EQ (tem, Qt))
+       return call1 (Vspecial_display_function, buffer);
+       if (CONSP (tem))
+       return call2 (Vspecial_display_function, buffer, tem);
+     }
+ 
+   /* If there are no frames open that have more than a minibuffer,
+      we need to create a new frame.  */
+   if (pop_up_frames || last_nonminibuf_frame == 0)
+     {
+       window = Fframe_selected_window (call0 (Vpop_up_frame_function));
+       Fset_window_buffer (window, buffer, Qnil);
+       return display_buffer_1 (window);
+     }
+ 
+   f = SELECTED_FRAME ();
+   if (pop_up_windows
+       || 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 (f))->dedicated))
+     {
+       Lisp_Object frames;
+ 
+       frames = Qnil;
+       if (FRAME_MINIBUF_ONLY_P (f))
+       XSETFRAME (frames, last_nonminibuf_frame);
+       /* Don't try to create a window if we would get an error.  */
+       if (split_height_threshold < window_min_height << 1)
+       split_height_threshold = window_min_height << 1;
+ 
+       /* Note that both Fget_largest_window and Fget_lru_window
+        ignore minibuffers and dedicated windows.
+        This means they can return nil.  */
+ 
+       /* If the frame we would try to split cannot be split,
+        try other frames.  */
+       if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
+       {
+         /* Try visible frames first.  */
+         window = Fget_largest_window (Qvisible);
+         /* If that didn't work, try iconified frames.  */
+         if (NILP (window))
+           window = Fget_largest_window (make_number (0));
+         if (NILP (window))
+           window = Fget_largest_window (Qt);
+       }
+       else
+       window = Fget_largest_window (frames);
+ 
+       /* If we got a tall enough full-width window that can be split,
+        split it.  */
+       if (!NILP (window)
+         && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
+         && window_height (window) >= split_height_threshold
+         && WINDOW_FULL_WIDTH_P (XWINDOW (window)))
+       window = Fsplit_window (window, Qnil, Qnil);
+       else
+       {
+         Lisp_Object upper, lower, other;
+ 
+         window = Fget_lru_window (frames);
+         /* If the LRU window is selected, and big enough,
+            and can be split, split it.  */
+         if (!NILP (window)
+             && ! FRAME_NO_SPLIT_P (XFRAME (XWINDOW (window)->frame))
+             && (EQ (window, selected_window)
+                 || EQ (XWINDOW (window)->parent, Qnil))
+             && window_height (window) >= window_min_height << 1)
+           window = Fsplit_window (window, Qnil, Qnil);
+         /* If Fget_lru_window returned nil, try other approaches.  */
+ 
+         /* Try visible frames first.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, Qvisible);
+         if (NILP (window))
+           window = Fget_largest_window (Qvisible);
+         /* If that didn't work, try iconified frames.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, make_number (0));
+         if (NILP (window))
+           window = Fget_largest_window (make_number (0));
+         /* Try invisible frames.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, Qt);
+         if (NILP (window))
+           window = Fget_largest_window (Qt);
+         /* As a last resort, make a new frame.  */
+         if (NILP (window))
+           window = Fframe_selected_window (call0 (Vpop_up_frame_function));
+         /* If window appears above or below another,
+            even out their heights.  */
+         other = upper = lower = Qnil;
+         if (!NILP (XWINDOW (window)->prev))
+           other = upper = XWINDOW (window)->prev, lower = window;
+         if (!NILP (XWINDOW (window)->next))
+           other = lower = XWINDOW (window)->next, upper = window;
+         if (!NILP (other)
+             && !NILP (Veven_window_heights)
+             /* Check that OTHER and WINDOW are vertically arrayed.  */
+             && !EQ (XWINDOW (other)->top_line, XWINDOW (window)->top_line)
+             && (XFASTINT (XWINDOW (other)->total_lines)
+                 > XFASTINT (XWINDOW (window)->total_lines)))
+           {
+             int total = (XFASTINT (XWINDOW (other)->total_lines)
+                          + XFASTINT (XWINDOW (window)->total_lines));
+             enlarge_window (upper,
+                             total / 2 - XFASTINT (XWINDOW 
(upper)->total_lines),
+                             0, 0);
+           }
+       }
+     }
+   else
+     window = Fget_lru_window (Qnil);
+ 
+   Fset_window_buffer (window, buffer, Qnil);
+   return display_buffer_1 (window);
+ }
+ 
+ 
+ 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
+ displaying that buffer.  */)
+      (object)
+      Lisp_Object object;
+ {
+   if (NILP (object))
+     {
+       windows_or_buffers_changed++;
+       update_mode_lines++;
+       return Qt;
+     }
+ 
+   if (WINDOWP (object))
+     {
+       struct window *w = XWINDOW (object);
+       mark_window_display_accurate (object, 0);
+       w->update_mode_line = Qt;
+       if (BUFFERP (w->buffer))
+       XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+       ++update_mode_lines;
+       return Qt;
+     }
+ 
+   if (STRINGP (object))
+     object = Fget_buffer (object);
+   if (BUFFERP (object) && !NILP (XBUFFER (object)->name))
+     {
+       /* Walk all windows looking for buffer, and force update
+        of each of those windows.  */
+ 
+       object = window_loop (REDISPLAY_BUFFER_WINDOWS, object, 0, Qvisible);
+       return NILP (object) ? Qnil : Qt;
+     }
+ 
+   /* If nothing suitable was found, just return.
+      We could signal an error, but this feature will typically be used
+      asynchronously in timers or process sentinels, so we don't.  */
+   return Qnil;
+ }
+ 
+ 
+ void
+ temp_output_buffer_show (buf)
+      register Lisp_Object buf;
+ {
+   register struct buffer *old = current_buffer;
+   register Lisp_Object window;
+   register struct window *w;
+ 
+   XBUFFER (buf)->directory = current_buffer->directory;
+ 
+   Fset_buffer (buf);
+   BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
+   BEGV = BEG;
+   ZV = Z;
+   SET_PT (BEG);
+ #if 0  /* rms: there should be no reason for this.  */
+   XBUFFER (buf)->prevent_redisplay_optimizations_p = 1;
+ #endif
+   set_buffer_internal (old);
+ 
+   if (!EQ (Vtemp_buffer_show_function, Qnil))
+     call1 (Vtemp_buffer_show_function, buf);
+   else
+     {
+       window = Fdisplay_buffer (buf, Qnil, Qnil);
+ 
+       if (!EQ (XWINDOW (window)->frame, selected_frame))
+       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
+       Vminibuf_scroll_window = window;
+       w = XWINDOW (window);
+       XSETFASTINT (w->hscroll, 0);
+       XSETFASTINT (w->min_hscroll, 0);
+       set_marker_restricted_both (w->start, buf, BEG, BEG);
+       set_marker_restricted_both (w->pointm, buf, BEG, BEG);
+ 
+       /* Run temp-buffer-show-hook, with the chosen window selected
+        and its buffer current.  */
+ 
+       if (!NILP (Vrun_hooks)
+         && !NILP (Fboundp (Qtemp_buffer_show_hook))
+         && !NILP (Fsymbol_value (Qtemp_buffer_show_hook)))
+       {
+         int count = SPECPDL_INDEX ();
+         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,
+            so we need to save the current buffer.  --stef  */
+         record_unwind_protect (Fset_buffer, prev_buffer);
+         record_unwind_protect (select_window_norecord, prev_window);
+         Fselect_window (window, Qt);
+         Fset_buffer (w->buffer);
+         call1 (Vrun_hooks, Qtemp_buffer_show_hook);
+         unbind_to (count, Qnil);
+       }
+     }
+ }
+ 
+ static void
+ make_dummy_parent (window)
+      Lisp_Object window;
+ {
+   Lisp_Object new;
+   register struct window *o, *p;
+   int i;
+ 
+   o = XWINDOW (window);
+   p = allocate_window ();
+   for (i = 0; i < VECSIZE (struct window); ++i)
+     ((struct Lisp_Vector *) p)->contents[i]
+       = ((struct Lisp_Vector *)o)->contents[i];
+   XSETWINDOW (new, p);
+ 
+   XSETFASTINT (p->sequence_number, ++sequence_number);
+ 
+   /* Put new into window structure in place of window */
+   replace_window (window, new);
+ 
+   o->next = Qnil;
+   o->prev = Qnil;
+   o->vchild = Qnil;
+   o->hchild = Qnil;
+   o->parent = new;
+ 
+   p->start = Qnil;
+   p->pointm = Qnil;
+   p->buffer = Qnil;
+ }
+ 
+ DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "",
+        doc: /* Split WINDOW, putting SIZE lines in the first of the pair.
+ 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.
+ 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;
+ {
+   register Lisp_Object new;
+   register struct window *o, *p;
+   FRAME_PTR fo;
+   register int size_int;
+ 
+   if (NILP (window))
+     window = selected_window;
+   else
+     CHECK_LIVE_WINDOW (window);
+ 
+   o = XWINDOW (window);
+   fo = XFRAME (WINDOW_FRAME (o));
+ 
+   if (NILP (size))
+     {
+       if (!NILP (horflag))
+       /* Calculate the size of the left-hand window, by dividing
+          the usable space in columns by two.
+          We round up, since the left-hand window may include
+          a dividing line, while the right-hand may not.  */
+       size_int = (XFASTINT (o->total_cols) + 1) >> 1;
+       else
+       size_int = XFASTINT (o->total_lines) >> 1;
+     }
+   else
+     {
+       CHECK_NUMBER (size);
+       size_int = XINT (size);
+     }
+ 
+   if (MINI_WINDOW_P (o))
+     error ("Attempt to split minibuffer window");
+   else if (window_fixed_size_p (o, !NILP (horflag), 0))
+     error ("Attempt to split fixed-size window");
+ 
+   check_min_window_sizes ();
+ 
+   if (NILP (horflag))
+     {
+       if (size_int < window_min_height)
+       error ("Window height %d too small (after splitting)", size_int);
+       if (size_int + window_min_height > XFASTINT (o->total_lines))
+       error ("Window height %d too small (after splitting)",
+              XFASTINT (o->total_lines) - size_int);
+       if (NILP (o->parent)
+         || NILP (XWINDOW (o->parent)->vchild))
+       {
+         make_dummy_parent (window);
+         new = o->parent;
+         XWINDOW (new)->vchild = window;
+       }
+     }
+   else
+     {
+       if (size_int < window_min_width)
+       error ("Window width %d too small (after splitting)", size_int);
+ 
+       if (size_int + window_min_width > XFASTINT (o->total_cols))
+       error ("Window width %d too small (after splitting)",
+              XFASTINT (o->total_cols) - size_int);
+       if (NILP (o->parent)
+         || NILP (XWINDOW (o->parent)->hchild))
+       {
+         make_dummy_parent (window);
+         new = o->parent;
+         XWINDOW (new)->hchild = window;
+       }
+     }
+ 
+   /* Now we know that window's parent is a vertical combination
+      if we are dividing vertically, or a horizontal combination
+      if we are making side-by-side windows */
+ 
+   windows_or_buffers_changed++;
+   FRAME_WINDOW_SIZES_CHANGED (fo) = 1;
+   new = make_window ();
+   p = XWINDOW (new);
+ 
+   p->frame = o->frame;
+   p->next = o->next;
+   if (!NILP (p->next))
+     XWINDOW (p->next)->prev = new;
+   p->prev = window;
+   o->next = new;
+   p->parent = o->parent;
+   p->buffer = Qt;
+   p->window_end_valid = Qnil;
+   bzero (&p->last_cursor, sizeof p->last_cursor);
+ 
+   /* Duplicate special geometry settings.  */
+ 
+   p->left_margin_cols = o->left_margin_cols;
+   p->right_margin_cols = o->right_margin_cols;
+   p->left_fringe_width = o->left_fringe_width;
+   p->right_fringe_width = o->right_fringe_width;
+   p->fringes_outside_margins = o->fringes_outside_margins;
+   p->scroll_bar_width = o->scroll_bar_width;
+   p->vertical_scroll_bar_type = o->vertical_scroll_bar_type;
+ 
+   /* Apportion the available frame space among the two new windows */
+ 
+   if (!NILP (horflag))
+     {
+       p->total_lines = o->total_lines;
+       p->top_line = o->top_line;
+       XSETFASTINT (p->total_cols, XFASTINT (o->total_cols) - size_int);
+       XSETFASTINT (o->total_cols, size_int);
+       XSETFASTINT (p->left_col, XFASTINT (o->left_col) + size_int);
+       adjust_window_margins (p);
+       adjust_window_margins (o);
+     }
+   else
+     {
+       p->left_col = o->left_col;
+       p->total_cols = o->total_cols;
+       XSETFASTINT (p->total_lines, XFASTINT (o->total_lines) - size_int);
+       XSETFASTINT (o->total_lines, size_int);
+       XSETFASTINT (p->top_line, XFASTINT (o->top_line) + size_int);
+     }
+ 
+   /* Adjust glyph matrices.  */
+   adjust_glyphs (fo);
+ 
+   Fset_window_buffer (new, o->buffer, Qt);
+   return new;
+ }
+ 
+ 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.
+ 
+ Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
+ of the siblings above or to the left of the selected window.  Only
+ siblings to the right or below are changed.  */)
+      (arg, side, preserve_before)
+      register Lisp_Object arg, side, preserve_before;
+ {
+   CHECK_NUMBER (arg);
+   enlarge_window (selected_window, XINT (arg), !NILP (side),
+                 !NILP (preserve_before));
+ 
+   if (! NILP (Vwindow_configuration_change_hook))
+     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+ 
+   return Qnil;
+ }
+ 
+ DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "p",
+        doc: /* Make current window ARG lines smaller.
+ From program, optional second arg non-nil means shrink sideways arg columns.
+ Interactively, if an argument is not given, make the window one line smaller.
+ 
+ Optional third arg PRESERVE-BEFORE, if non-nil, means do not change the size
+ of the siblings above or to the left of the selected window.  Only
+ siblings to the right or below are changed.  */)
+      (arg, side, preserve_before)
+      register Lisp_Object arg, side, preserve_before;
+ {
+   CHECK_NUMBER (arg);
+   enlarge_window (selected_window, -XINT (arg), !NILP (side),
+                 !NILP (preserve_before));
+ 
+   if (! NILP (Vwindow_configuration_change_hook))
+     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+ 
+   return Qnil;
+ }
+ 
+ int
+ window_height (window)
+      Lisp_Object window;
+ {
+   register struct window *p = XWINDOW (window);
+   return WINDOW_TOTAL_LINES (p);
+ }
+ 
+ int
+ window_width (window)
+      Lisp_Object window;
+ {
+   register struct window *p = XWINDOW (window);
+   return WINDOW_TOTAL_COLS (p);
+ }
+ 
+ 
+ #define CURBEG(w) \
+   *(widthflag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
+ 
+ #define CURSIZE(w) \
+   *(widthflag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
+ 
+ 
+ /* Enlarge WINDOW by DELTA.  WIDTHFLAG non-zero means
+    increase its width.  Siblings of the selected window are resized to
+    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, preserve_before)
+      Lisp_Object window;
+      int delta, widthflag, preserve_before;
+ {
+   Lisp_Object parent, next, prev;
+   struct window *p;
+   Lisp_Object *sizep;
+   int maximum;
+   int (*sizefun) P_ ((Lisp_Object))
+     = widthflag ? window_width : window_height;
+   void (*setsizefun) P_ ((Lisp_Object, int, int))
+     = (widthflag ? set_window_width : set_window_height);
+ 
+   /* Check values of window_min_width and window_min_height for
+      validity.  */
+   check_min_window_sizes ();
+ 
+   /* Give up if this window cannot be resized.  */
+   if (window_fixed_size_p (XWINDOW (window), widthflag, 1))
+     error ("Window is not resizable");
+ 
+   /* Find the parent of the selected window.  */
+   while (1)
+     {
+       p = XWINDOW (window);
+       parent = p->parent;
+ 
+       if (NILP (parent))
+       {
+         if (widthflag)
+           error ("No other window to side of this one");
+         break;
+       }
+ 
+       if (widthflag
+         ? !NILP (XWINDOW (parent)->hchild)
+         : !NILP (XWINDOW (parent)->vchild))
+       break;
+ 
+       window = parent;
+     }
+ 
+   sizep = &CURSIZE (window);
+ 
+   {
+     register int maxdelta;
+ 
+     /* 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
+        the full frame, or make the only window aside from the
+        minibuffer the full frame.  */
+       delta = maxdelta;
+   }
+ 
+   if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 
0, 0))
+     {
+       delete_window (window);
+       return;
+     }
+ 
+   if (delta == 0)
+     return;
+ 
+   /* 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);
+   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 without deleting them, do so.  */
+   if (delta <= maximum)
+     {
+       Lisp_Object first_unaffected;
+       Lisp_Object first_affected;
+       int fixed_p;
+ 
+       next = p->next;
+       prev = p->prev;
+       first_affected = window;
+       /* 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) || (!preserve_before && !NILP (prev))))
+       {
+         if (! NILP (next))
+           {
+             int this_one = ((*sizefun) (next)
+                             - window_min_size (XWINDOW (next),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+ 
+                 (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
+                 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
+ 
+                 delta -= this_one;
+               }
+ 
+             next = XWINDOW (next)->next;
+           }
+ 
+         if (delta == 0)
+           break;
+ 
+         if (!preserve_before && ! NILP (prev))
+           {
+             int this_one = ((*sizefun) (prev)
+                             - window_min_size (XWINDOW (prev),
+                                                widthflag, 0, &fixed_p));
+             if (!fixed_p)
+               {
+                 if (this_one > delta)
+                   this_one = delta;
+ 
+                 first_affected = prev;
+ 
+                 (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
+                 (*setsizefun) (window, XINT (*sizep) + this_one, 0);
+ 
+                 delta -= this_one;
+               }
+ 
+             prev = XWINDOW (prev)->prev;
+           }
+       }
+ 
+       xassert (delta == 0);
+ 
+       /* Now recalculate the edge positions of all the windows affected,
+        based on the new sizes.  */
+       first_unaffected = next;
+       prev = first_affected;
+       for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
+          prev = next, next = XWINDOW (next)->next)
+       {
+         XSETINT (CURBEG (next), XINT (CURBEG (prev)) + (*sizefun) (prev));
+         /* This does not change size of NEXT,
+            but it propagates the new top edge to its children */
+         (*setsizefun) (next, (*sizefun) (next), 0);
+       }
+     }
+   else
+     {
+       register int delta1;
+       register int opht = (*sizefun) (parent);
+ 
+       if (opht <= XINT (*sizep) + delta)
+       {
+         /* 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
+            delta1 lines to this window and to the parent, and then
+            shrink the parent back to its original size, the new
+            proportional size of this window will increase by delta.
+ 
+            The function size_window will compute the new height h'
+            of the window from delta1 as:
+ 
+            e = delta1/n
+            x = delta1 - delta1/n * n for the 1st resizable child
+            h' = h + e + x
+ 
+            where n is the number of children that can be resized.
+            We can ignore x by choosing a delta1 that is a multiple of
+            n.  We want the height of this window to come out as
+ 
+            h' = h + delta
+ 
+            So, delta1 must be
+ 
+            h + e = h + delta
+            delta1/n = delta
+            delta1 = n * delta.
+ 
+            The number of children n equals the number of resizable
+            children of this window + 1 because we know window itself
+            is resizable (otherwise we would have signalled an error.  */
+ 
+         struct window *w = XWINDOW (window);
+         Lisp_Object s;
+         int n = 1;
+ 
+         for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
+           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+             ++n;
+         for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
+           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+             ++n;
+ 
+         delta1 = n * delta;
+ 
+         /* Add delta1 lines or columns to this window, and to the parent,
+            keeping things consistent while not affecting siblings.  */
+         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);
+   XSETFASTINT (p->last_overlay_modified, 0);
+ 
+   /* Adjust glyph matrices. */
+   adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
+ }
+ 
+ #undef CURBEG
+ #undef CURSIZE
+ 
+ 
+ 
+ /***********************************************************************
+                       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->total_lines);
+   XSETFASTINT (w->total_lines, height);
+ 
+   if (!NILP (w->hchild))
+     {
+       for (child = w->hchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top_line = w->top_line;
+         shrink_window_lowest_first (c, height);
+       }
+     }
+   else if (!NILP (w->vchild))
+     {
+       Lisp_Object last_child;
+       int delta = old_height - height;
+       int last_top;
+ 
+       last_child = Qnil;
+ 
+       /* 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->total_lines) - MIN_SAFE_WINDOW_HEIGHT;
+ 
+         if (this_one > delta)
+           this_one = delta;
+ 
+         shrink_window_lowest_first (c, XFASTINT (c->total_lines) - this_one);
+         delta -= this_one;
+       }
+ 
+       /* Compute new positions.  */
+       last_top = XINT (w->top_line);
+       for (child = w->vchild; !NILP (child); child = c->next)
+       {
+         c = XWINDOW (child);
+         c->top_line = make_number (last_top);
+         shrink_window_lowest_first (c, XFASTINT (c->total_lines));
+         last_top += XFASTINT (c->total_lines);
+       }
+     }
+ }
+ 
+ 
+ /* 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_line and
+    orig_total_lines 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_line and orig_total_lines for all windows in the tree.
+ 
+    If ACTION is RESTORE_ORIG_SIZES, restore top and height from values
+    stored in orig_top_line and orig_total_lines 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_line) || !INTEGERP (w->orig_total_lines))
+           return 0;
+         break;
+ 
+       case SAVE_ORIG_SIZES:
+         w->orig_top_line = w->top_line;
+         w->orig_total_lines = w->total_lines;
+           XSETFASTINT (w->last_modified, 0);
+           XSETFASTINT (w->last_overlay_modified, 0);
+         break;
+ 
+       case RESTORE_ORIG_SIZES:
+         xassert (INTEGERP (w->orig_top_line) && INTEGERP 
(w->orig_total_lines));
+         w->top_line = w->orig_top_line;
+         w->total_lines = w->orig_total_lines;
+         w->orig_total_lines = w->orig_top_line = 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->total_lines) - delta < min_height)
+       /* Note that the root window may already be smaller than
+          min_height.  */
+       delta = max (0, XFASTINT (root->total_lines) - 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->total_lines) - delta);
+ 
+       /* Grow the mini-window.  */
+       w->top_line = make_number (XFASTINT (root->top_line) + XFASTINT 
(root->total_lines));
+       w->total_lines = make_number (XFASTINT (w->total_lines) + 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->total_lines) > 1)
+     {
+       /* Distribute the additional lines of the mini-window
+        among the other windows.  */
+       Lisp_Object window;
+       XSETWINDOW (window, w);
+       enlarge_window (window, 1 - XFASTINT (w->total_lines), 0, 0);
+     }
+ }
+ 
+ 
+ 
+ /* Mark window cursors off for all windows in the window tree rooted
+    at W by setting their phys_cursor_on_p flag to zero.  Called from
+    xterm.c, e.g. when a frame is cleared and thereby all cursors on
+    the frame are cleared.  */
+ 
+ void
+ mark_window_cursors_off (w)
+      struct window *w;
+ {
+   while (w)
+     {
+       if (!NILP (w->hchild))
+       mark_window_cursors_off (XWINDOW (w->hchild));
+       else if (!NILP (w->vchild))
+       mark_window_cursors_off (XWINDOW (w->vchild));
+       else
+       w->phys_cursor_on_p = 0;
+ 
+       w = NILP (w->next) ? 0 : XWINDOW (w->next);
+     }
+ }
+ 
+ 
+ /* Return number of lines of text (not counting mode lines) in W.  */
+ 
+ int
+ window_internal_height (w)
+      struct window *w;
+ {
+   int ht = XFASTINT (w->total_lines);
+ 
+   if (!MINI_WINDOW_P (w))
+     {
+       if (!NILP (w->parent)
+         || !NILP (w->vchild)
+         || !NILP (w->hchild)
+         || !NILP (w->next)
+         || !NILP (w->prev)
+         || WINDOW_WANTS_MODELINE_P (w))
+       --ht;
+ 
+       if (WINDOW_WANTS_HEADER_LINE_P (w))
+       --ht;
+     }
+ 
+   return ht;
+ }
+ 
+ 
+ /* Return the number of columns in W.
+    Don't count columns occupied by scroll bars or the vertical bar
+    separating W from the sibling to its right.  */
+ 
+ int
+ window_box_text_cols (w)
+      struct window *w;
+ {
+   struct frame *f = XFRAME (WINDOW_FRAME (w));
+   int width = XINT (w->total_cols);
+ 
+   if (WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
+     /* Scroll bars occupy a few columns.  */
+     width -= WINDOW_CONFIG_SCROLL_BAR_COLS (w);
+   else if (!FRAME_WINDOW_P (f)
+          && !WINDOW_RIGHTMOST_P (w) && !WINDOW_FULL_WIDTH_P (w))
+     /* The column of `|' characters separating side-by-side windows
+        occupies one column only.  */
+     width -= 1;
+ 
+   if (FRAME_WINDOW_P (f))
+     /* On window-systems, fringes and display margins cannot be
+        used for normal text.  */
+     width -= (WINDOW_FRINGE_COLS (w)
+             + WINDOW_LEFT_MARGIN_COLS (w)
+             + WINDOW_RIGHT_MARGIN_COLS (w));
+ 
+   return width;
+ }
+ 
+ 
+ /************************************************************************
+                          Window Scrolling
+  ***********************************************************************/
+ 
+ /* Scroll contents of window WINDOW up.  If WHOLE is non-zero, scroll
+    N screen-fulls, which is defined as the height of the window minus
+    next_screen_context_lines.  If WHOLE is zero, scroll up N lines
+    instead.  Negative values of N mean scroll down.  NOERROR non-zero
+    means don't signal an error if we try to move over BEGV or ZV,
+    respectively.  */
+ 
+ static void
+ window_scroll (window, n, whole, noerror)
+      Lisp_Object window;
+      int n;
+      int whole;
+      int noerror;
+ {
+   immediate_quit = 1;
+ 
+   /* If we must, use the pixel-based version which is much slower than
+      the line-based one but can handle varying line heights.  */
+   if (FRAME_WINDOW_P (XFRAME (XWINDOW (window)->frame)))
+     window_scroll_pixel_based (window, n, whole, noerror);
+   else
+     window_scroll_line_based (window, n, whole, noerror);
+ 
+   immediate_quit = 0;
+ }
+ 
+ 
+ /* Implementation of window_scroll that works based on pixel line
+    heights.  See the comment of window_scroll for parameter
+    descriptions.  */
+ 
+ static void
+ window_scroll_pixel_based (window, n, whole, noerror)
+      Lisp_Object window;
+      int n;
+      int whole;
+      int noerror;
+ {
+   struct it it;
+   struct window *w = XWINDOW (window);
+   struct text_pos start;
+   Lisp_Object tem;
+   int this_scroll_margin;
+   int preserve_y;
+   /* True if we fiddled the window vscroll field without really scrolling.   
*/
+   int vscrolled = 0;
+ 
+   SET_TEXT_POS_FROM_MARKER (start, w->start);
+ 
+   /* If PT is not visible in WINDOW, move back one half of
+      the screen.  Allow PT to be partially visible, otherwise
+      something like (scroll-down 1) with PT in the line before
+      the partially visible one would recenter. */
+   tem = Fpos_visible_in_window_p (make_number (PT), window, Qt);
+   if (NILP (tem))
+     {
+       /* Move backward half the height of the window.  Performance note:
+        vmotion used here is about 10% faster, but would give wrong
+        results for variable height lines.  */
+       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+       it.current_y = it.last_visible_y;
+       move_it_vertically (&it, - 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
+        mini-buffer window, we may end up in front of the window's
+        display area.  This is the case when Start displaying at the
+        start of the line containing PT in this case.  */
+       if (it.current_y <= 0)
+       {
+         init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+         move_it_vertically (&it, 0);
+         it.current_y = 0;
+       }
+ 
+       start = it.current.pos;
+     }
+ 
+   /* If scroll_preserve_screen_position is non-zero, we try to set
+      point in the same window line as it is now, so get that line.  */
+   if (!NILP (Vscroll_preserve_screen_position))
+     {
+       start_display (&it, w, start);
+       move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+       preserve_y = it.current_y;
+     }
+   else
+     preserve_y = -1;
+ 
+   /* Move iterator it from start the specified distance forward or
+      backward.  The result is the new window start.  */
+   start_display (&it, w, start);
+   if (whole)
+     {
+       int screen_full = (window_box_height (w)
+                        - next_screen_context_lines * FRAME_LINE_HEIGHT 
(it.f));
+       int dy = n * screen_full;
+ 
+       /* Note that move_it_vertically always moves the iterator to the
+          start of a line.  So, if the last line doesn't have a newline,
+        we would end up at the start of the line ending at ZV.  */
+       if (dy <= 0)
+       move_it_vertically_backward (&it, -dy);
+       else if (dy > 0)
+       move_it_to (&it, ZV, -1, it.current_y + dy, -1,
+                   MOVE_TO_POS | MOVE_TO_Y);
+     }
+   else
+     move_it_by_lines (&it, n, 1);
+ 
+   /* We failed if we find ZV is already on the screen (scrolling up,
+      means there's nothing past the end), or if we can't start any
+      earlier (scrolling down, means there's nothing past the top).  */
+   if ((n > 0 && IT_CHARPOS (it) == ZV)
+       || (n < 0 && IT_CHARPOS (it) == CHARPOS (start)))
+     {
+       if (IT_CHARPOS (it) == ZV)
+       {
+         if (it.current_y < it.last_visible_y
+             && (it.current_y + it.max_ascent + it.max_descent
+                 >= it.last_visible_y))
+           {
+             /* The last line was only partially visible, make it fully
+                visible.  */
+             w->vscroll = (it.last_visible_y
+                           - it.current_y + it.max_ascent + it.max_descent);
+             adjust_glyphs (it.f);
+           }
+         else if (noerror)
+           return;
+         else
+           Fsignal (Qend_of_buffer, Qnil);
+       }
+       else
+       {
+         if (w->vscroll != 0)
+           /* The first line was only partially visible, make it fully
+              visible. */
+           w->vscroll = 0;
+         else if (noerror)
+           return;
+         else
+           Fsignal (Qbeginning_of_buffer, Qnil);
+       }
+ 
+       /* If control gets here, then we vscrolled.  */
+ 
+       XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+ 
+       /* Don't try to change the window start below.  */
+       vscrolled = 1;
+     }
+ 
+   if (! vscrolled)
+     {
+       int pos = IT_CHARPOS (it);
+       int bytepos;
+ 
+       /* If in the middle of a multi-glyph character move forward to
+        the next character.  */
+       if (in_display_vector_p (&it))
+       {
+         ++pos;
+         move_it_to (&it, pos, -1, -1, -1, MOVE_TO_POS);
+       }
+ 
+       /* Set the window start, and set up the window for redisplay.  */
+       set_marker_restricted (w->start, make_number (pos),
+                            w->buffer);
+       bytepos = XMARKER (w->start)->bytepos;
+       w->start_at_line_beg = ((pos == BEGV || FETCH_BYTE (bytepos - 1) == 
'\n')
+                             ? Qt : Qnil);
+       w->update_mode_line = Qt;
+       XSETFASTINT (w->last_modified, 0);
+       XSETFASTINT (w->last_overlay_modified, 0);
+       /* Set force_start so that redisplay_window will run the
+        window-scroll-functions.  */
+       w->force_start = Qt;
+     }
+ 
+   it.current_y = it.vpos = 0;
+ 
+   /* Preserve the screen position if we must.  */
+   if (preserve_y >= 0)
+     {
+       move_it_to (&it, -1, -1, preserve_y, -1, MOVE_TO_Y);
+       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+     }
+   else
+     {
+       /* Move PT out of scroll margins.  */
+       this_scroll_margin = max (0, scroll_margin);
+       this_scroll_margin = min (this_scroll_margin, XFASTINT (w->total_lines) 
/ 4);
+       this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+ 
+       if (n > 0)
+       {
+         /* We moved the window start towards ZV, so PT may be now
+            in the scroll margin at the top.  */
+         move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+         while (it.current_y < this_scroll_margin)
+           {
+             int prev = it.current_y;
+             move_it_by_lines (&it, 1, 1);
+             if (prev == it.current_y)
+               break;
+           }
+         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+       }
+       else if (n < 0)
+       {
+         int charpos, bytepos;
+ 
+         /* We moved the window start towards BEGV, so PT may be now
+            in the scroll margin at the bottom.  */
+         move_it_to (&it, PT, -1,
+                     it.last_visible_y - this_scroll_margin - 1, -1,
+                     MOVE_TO_POS | MOVE_TO_Y);
+ 
+         /* Save our position, in case it's correct.  */
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+ 
+         /* See if point is on a partially visible line at the end.  */
+         move_it_by_lines (&it, 1, 1);
+         if (it.current_y > it.last_visible_y)
+           /* The last line was only partially visible, so back up two
+              lines to make sure we're on a fully visible line.  */
+           {
+             move_it_by_lines (&it, -2, 0);
+             SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+           }
+         else
+           /* No, the position we saved is OK, so use it.  */
+           SET_PT_BOTH (charpos, bytepos);
+       }
+     }
+ }
+ 
+ 
+ /* Implementation of window_scroll that works based on screen lines.
+    See the comment of window_scroll for parameter descriptions.  */
+ 
+ static void
+ window_scroll_line_based (window, n, whole, noerror)
+      Lisp_Object window;
+      int n;
+      int whole;
+      int noerror;
+ {
+   register struct window *w = XWINDOW (window);
+   register int opoint = PT, opoint_byte = PT_BYTE;
+   register int pos, pos_byte;
+   register int ht = window_internal_height (w);
+   register Lisp_Object tem;
+   int lose;
+   Lisp_Object bolp;
+   int startpos;
+   struct position posit;
+   int original_vpos;
+ 
+   /* If scrolling screen-fulls, compute the number of lines to
+      scroll from the window's height.  */
+   if (whole)
+     n *= max (1, ht - next_screen_context_lines);
+ 
+   startpos = marker_position (w->start);
+ 
+   posit = *compute_motion (startpos, 0, 0, 0,
+                          PT, ht, 0,
+                          -1, XINT (w->hscroll),
+                          0, w);
+   original_vpos = posit.vpos;
+ 
+   XSETFASTINT (tem, PT);
+   tem = Fpos_visible_in_window_p (tem, window, Qnil);
+ 
+   if (NILP (tem))
+     {
+       Fvertical_motion (make_number (- (ht / 2)), window);
+       startpos = PT;
+     }
+ 
+   SET_PT (startpos);
+   lose = n < 0 && PT == BEGV;
+   Fvertical_motion (make_number (n), window);
+   pos = PT;
+   pos_byte = PT_BYTE;
+   bolp = Fbolp ();
+   SET_PT_BOTH (opoint, opoint_byte);
+ 
+   if (lose)
+     {
+       if (noerror)
+       return;
+       else
+       Fsignal (Qbeginning_of_buffer, Qnil);
+     }
+ 
+   if (pos < ZV)
+     {
+       int this_scroll_margin = scroll_margin;
+ 
+       /* Don't use a scroll margin that is negative or too large.  */
+       if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+ 
+       if (XINT (w->total_lines) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->total_lines) / 4;
+ 
+       set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
+       w->start_at_line_beg = bolp;
+       w->update_mode_line = Qt;
+       XSETFASTINT (w->last_modified, 0);
+       XSETFASTINT (w->last_overlay_modified, 0);
+       /* Set force_start so that redisplay_window will run
+        the window-scroll-functions.  */
+       w->force_start = Qt;
+ 
+       if (whole && !NILP (Vscroll_preserve_screen_position))
+       {
+         SET_PT_BOTH (pos, pos_byte);
+         Fvertical_motion (make_number (original_vpos), window);
+       }
+       /* If we scrolled forward, put point enough lines down
+        that it is outside the scroll margin.  */
+       else if (n > 0)
+       {
+         int top_margin;
+ 
+         if (this_scroll_margin > 0)
+           {
+             SET_PT_BOTH (pos, pos_byte);
+             Fvertical_motion (make_number (this_scroll_margin), window);
+             top_margin = PT;
+           }
+         else
+           top_margin = pos;
+ 
+         if (top_margin <= opoint)
+           SET_PT_BOTH (opoint, opoint_byte);
+         else if (!NILP (Vscroll_preserve_screen_position))
+           {
+             SET_PT_BOTH (pos, pos_byte);
+             Fvertical_motion (make_number (original_vpos), window);
+           }
+         else
+           SET_PT (top_margin);
+       }
+       else if (n < 0)
+       {
+         int bottom_margin;
+ 
+         /* If we scrolled backward, put point near the end of the window
+            but not within the scroll margin.  */
+         SET_PT_BOTH (pos, pos_byte);
+         tem = Fvertical_motion (make_number (ht - this_scroll_margin), 
window);
+         if (XFASTINT (tem) == ht - this_scroll_margin)
+           bottom_margin = PT;
+         else
+           bottom_margin = PT + 1;
+ 
+         if (bottom_margin > opoint)
+           SET_PT_BOTH (opoint, opoint_byte);
+         else
+           {
+             if (!NILP (Vscroll_preserve_screen_position))
+               {
+                 SET_PT_BOTH (pos, pos_byte);
+                 Fvertical_motion (make_number (original_vpos), window);
+               }
+             else
+               Fvertical_motion (make_number (-1), window);
+           }
+       }
+     }
+   else
+     {
+       if (noerror)
+       return;
+       else
+       Fsignal (Qend_of_buffer, Qnil);
+     }
+ }
+ 
+ 
+ /* Scroll selected_window up or down.  If N is nil, scroll a
+    screen-full which is defined as the height of the window minus
+    next_screen_context_lines.  If N is the symbol `-', scroll.
+    DIRECTION may be 1 meaning to scroll down, or -1 meaning to scroll
+    up.  This is the guts of Fscroll_up and Fscroll_down.  */
+ 
+ static void
+ scroll_command (n, direction)
+      Lisp_Object n;
+      int direction;
+ {
+   int count = SPECPDL_INDEX ();
+ 
+   xassert (abs (direction) == 1);
+ 
+   /* If selected window's buffer isn't current, make it current for
+      the moment.  But don't screw up if window_scroll gets an error.  */
+   if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+     {
+       record_unwind_protect (save_excursion_restore, save_excursion_save ());
+       Fset_buffer (XWINDOW (selected_window)->buffer);
+ 
+       /* Make redisplay consider other windows than just selected_window.  */
+       ++windows_or_buffers_changed;
+     }
+ 
+   if (NILP (n))
+     window_scroll (selected_window, direction, 1, 0);
+   else if (EQ (n, Qminus))
+     window_scroll (selected_window, -direction, 1, 0);
+   else
+     {
+       n = Fprefix_numeric_value (n);
+       window_scroll (selected_window, XINT (n) * direction, 0, 0);
+     }
+ 
+   unbind_to (count, Qnil);
+ }
+ 
+ DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
+        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.
+ When calling from a program, supply as argument a number, nil, or `-'.  */)
+      (arg)
+      Lisp_Object arg;
+ {
+   scroll_command (arg, 1);
+   return Qnil;
+ }
+ 
+ DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
+        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.
+ When calling from a program, supply as argument a number, nil, or `-'.  */)
+      (arg)
+      Lisp_Object arg;
+ {
+   scroll_command (arg, -1);
+   return Qnil;
+ }
+ 
+ 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 `other-window-scroll-buffer' is non-nil, a window
+ 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;
+ 
+   if (MINI_WINDOW_P (XWINDOW (selected_window))
+       && !NILP (Vminibuf_scroll_window))
+     window = Vminibuf_scroll_window;
+   /* If buffer is specified, scroll that buffer.  */
+   else if (!NILP (Vother_window_scroll_buffer))
+     {
+       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
+       if (NILP (window))
+       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
+     }
+   else
+     {
+       /* Nothing specified; look for a neighboring window on the same
+        frame.  */
+       window = Fnext_window (selected_window, Qnil, Qnil);
+ 
+       if (EQ (window, selected_window))
+       /* That didn't get us anywhere; look for a window on another
+            visible frame.  */
+       do
+         window = Fnext_window (window, Qnil, Qt);
+       while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
+              && ! EQ (window, selected_window));
+     }
+ 
+   CHECK_LIVE_WINDOW (window);
+ 
+   if (EQ (window, selected_window))
+     error ("There is no other window");
+ 
+   return window;
+ }
+ 
+ DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 
1, "P",
+        doc: /* Scroll next window upward ARG lines; or near full screen if no 
ARG.
+ A near full screen is `next-screen-context-lines' less than a full screen.
+ The next window is the one below the current one; or the one at the top
+ 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 `other-window-scroll-buffer' is non-nil, scroll the window
+ 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;
+ {
+   Lisp_Object window;
+   struct window *w;
+   int count = SPECPDL_INDEX ();
+ 
+   window = Fother_window_for_scrolling ();
+   w = XWINDOW (window);
+ 
+   /* Don't screw up if window_scroll gets an error.  */
+   record_unwind_protect (save_excursion_restore, save_excursion_save ());
+   ++windows_or_buffers_changed;
+ 
+   Fset_buffer (w->buffer);
+   SET_PT (marker_position (w->pointm));
+ 
+   if (NILP (arg))
+     window_scroll (window, 1, 1, 1);
+   else if (EQ (arg, Qminus))
+     window_scroll (window, -1, 1, 1);
+   else
+     {
+       if (CONSP (arg))
+       arg = Fcar (arg);
+       CHECK_NUMBER (arg);
+       window_scroll (window, XINT (arg), 0, 1);
+     }
+ 
+   set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
+   unbind_to (count, Qnil);
+ 
+   return Qnil;
+ }
+ 
+ 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.
+ 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;
+ {
+   Lisp_Object result;
+   int hscroll;
+   struct window *w = XWINDOW (selected_window);
+ 
+   if (NILP (arg))
+     XSETFASTINT (arg, window_box_text_cols (w) - 2);
+   else
+     arg = Fprefix_numeric_value (arg);
+ 
+   hscroll = XINT (w->hscroll) + XINT (arg);
+   result = Fset_window_hscroll (selected_window, make_number (hscroll));
+ 
+   if (interactive_p (0))
+     w->min_hscroll = w->hscroll;
+ 
+   return result;
+ }
+ 
+ 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.
+ 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;
+ {
+   Lisp_Object result;
+   int hscroll;
+   struct window *w = XWINDOW (selected_window);
+ 
+   if (NILP (arg))
+     XSETFASTINT (arg, window_box_text_cols (w) - 2);
+   else
+     arg = Fprefix_numeric_value (arg);
+ 
+   hscroll = XINT (w->hscroll) - XINT (arg);
+   result = Fset_window_hscroll (selected_window, make_number (hscroll));
+ 
+   if (interactive_p (0))
+     w->min_hscroll = w->hscroll;
+ 
+   return result;
+ }
+ 
+ DEFUN ("minibuffer-selected-window", Fminibuffer_selected_window, 
Sminibuffer_selected_window, 0, 0, 0,
+        doc: /* Return the window which was selected when entering the 
minibuffer.
+ Returns nil, if current window is not a minibuffer window.  */)
+      ()
+ {
+   if (minibuf_level > 0
+       && MINI_WINDOW_P (XWINDOW (selected_window))
+       && WINDOW_LIVE_P (minibuf_selected_window))
+     return minibuf_selected_window;
+ 
+   return Qnil;
+ }
+ 
+ /* Value is the number of lines actually displayed in window W,
+    as opposed to its height.  */
+ 
+ static int
+ displayed_window_lines (w)
+      struct window *w;
+ {
+   struct it it;
+   struct text_pos start;
+   int height = window_box_height (w);
+   struct buffer *old_buffer;
+   int bottom_y;
+ 
+   if (XBUFFER (w->buffer) != current_buffer)
+     {
+       old_buffer = current_buffer;
+       set_buffer_internal (XBUFFER (w->buffer));
+     }
+   else
+     old_buffer = NULL;
+ 
+   /* In case W->start is out of the accessible range, do something
+      reasonable.  This happens in Info mode when Info-scroll-down
+      calls (recenter -1) while W->start is 1.  */
+   if (XMARKER (w->start)->charpos < BEGV)
+     SET_TEXT_POS (start, BEGV, BEGV_BYTE);
+   else if (XMARKER (w->start)->charpos > ZV)
+     SET_TEXT_POS (start, ZV, ZV_BYTE);
+   else
+     SET_TEXT_POS_FROM_MARKER (start, w->start);
+ 
+   start_display (&it, w, start);
+   move_it_vertically (&it, height);
+   bottom_y = line_bottom_y (&it);
+ 
+   /* rms: On a non-window display,
+      the value of it.vpos at the bottom of the screen
+      seems to be 1 larger than window_box_height (w).
+      This kludge fixes a bug whereby (move-to-window-line -1)
+      when ZV is on the last screen line
+      moves to the previous screen line instead of the last one.  */
+   if (! FRAME_WINDOW_P (XFRAME (w->frame)))
+     height++;
+ 
+   /* Add in empty lines at the bottom of the window.  */
+   if (bottom_y < height)
+     {
+       int uy = FRAME_LINE_HEIGHT (it.f);
+       it.vpos += (height - bottom_y + uy - 1) / uy;
+     }
+ 
+   if (old_buffer)
+     set_buffer_internal (old_buffer);
+ 
+   return it.vpos;
+ }
+ 
+ 
+ DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
+        doc: /* Center point in window and redisplay frame.
+ With prefix argument ARG, recenter putting point on screen line ARG
+ relative to the current window.  If ARG is negative, it counts up from the
+ bottom of the window.  (ARG should be less than the height of the window.)
+ 
+ If ARG is omitted or nil, erase the entire frame and then
+ redraw with point in the center of the current window.
+ Just C-u as prefix means put point in the center of the window
+ and redisplay normally--don't erase and redraw the frame.  */)
+      (arg)
+      register Lisp_Object arg;
+ {
+   struct window *w = XWINDOW (selected_window);
+   struct buffer *buf = XBUFFER (w->buffer);
+   struct buffer *obuf = current_buffer;
+   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;
+ 
+       /* Invalidate pixel data calculated for all compositions.  */
+       for (i = 0; i < n_compositions; i++)
+       composition_table[i]->font = NULL;
+ 
+       Fredraw_frame (w->frame);
+       SET_FRAME_GARBAGED (XFRAME (WINDOW_FRAME (w)));
+       center_p = 1;
+     }
+   else if (CONSP (arg)) /* Just C-u. */
+     center_p = 1;
+   else
+     {
+       arg = Fprefix_numeric_value (arg);
+       CHECK_NUMBER (arg);
+     }
+ 
+   set_buffer_internal (buf);
+ 
+   /* Handle centering on a graphical frame specially.  Such frames can
+      have variable-height lines and centering point on the basis of
+      line counts would lead to strange effects.  */
+   if (FRAME_WINDOW_P (XFRAME (w->frame)))
+     {
+       if (center_p)
+       {
+         struct it it;
+         struct text_pos pt;
+ 
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+         move_it_vertically (&it, - window_box_height (w) / 2);
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+       }
+       else if (XINT (arg) < 0)
+       {
+         struct it it;
+         struct text_pos pt;
+         int y0, y1, h, nlines;
+ 
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+         y0 = it.current_y;
+ 
+         /* 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;
+         move_it_by_lines (&it, nlines, 1);
+ 
+         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) * FRAME_LINE_HEIGHT (it.f);
+ 
+         h = window_box_height (w) - (y1 - y0);
+ 
+         start_display (&it, w, pt);
+         move_it_vertically (&it, - h);
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+       }
+       else
+       {
+         struct position pos;
+         pos = *vmotion (PT, - XINT (arg), w);
+         charpos = pos.bufpos;
+         bytepos = pos.bytepos;
+       }
+     }
+   else
+     {
+       struct position pos;
+       int ht = window_internal_height (w);
+ 
+       if (center_p)
+       arg = make_number (ht / 2);
+       else if (XINT (arg) < 0)
+       arg = make_number (XINT (arg) + ht);
+ 
+       pos = *vmotion (PT, - XINT (arg), w);
+       charpos = pos.bufpos;
+       bytepos = pos.bytepos;
+     }
+ 
+   /* Set the new window start.  */
+   set_marker_both (w->start, w->buffer, charpos, bytepos);
+   w->window_end_valid = Qnil;
+ 
+   w->optional_new_start = Qt;
+ 
+   if (bytepos == BEGV_BYTE || FETCH_BYTE (bytepos - 1) == '\n')
+     w->start_at_line_beg = Qt;
+   else
+     w->start_at_line_beg = Qnil;
+ 
+   set_buffer_internal (obuf);
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("window-text-height", Fwindow_text_height, Swindow_text_height,
+        0, 1, 0,
+        doc: /* Return the height in lines of the text display area of WINDOW.
+ This doesn't include the mode-line (or header-line if any) or any
+ partial-height lines in the text display area.  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w = decode_window (window);
+   int pixel_height = window_box_height (w);
+   int line_height = pixel_height / FRAME_LINE_HEIGHT (XFRAME (w->frame));
+   return make_number (line_height);
+ }
+ 
+ 
+ 
+ DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
+        1, 1, "P",
+        doc: /* Position point relative to window.
+ With no argument, position point at center of window.
+ An argument specifies vertical position within the window;
+ zero means top of window, negative means relative to bottom of window.  */)
+      (arg)
+      Lisp_Object arg;
+ {
+   struct window *w = XWINDOW (selected_window);
+   int lines, start;
+   Lisp_Object window;
+ 
+   window = selected_window;
+   start = marker_position (w->start);
+   if (start < BEGV || start > ZV)
+     {
+       int height = window_internal_height (w);
+       Fvertical_motion (make_number (- (height / 2)), window);
+       set_marker_both (w->start, w->buffer, PT, PT_BYTE);
+       w->start_at_line_beg = Fbolp ();
+       w->force_start = Qt;
+     }
+   else
+     Fgoto_char (w->start);
+ 
+   lines = displayed_window_lines (w);
+   if (NILP (arg))
+     XSETFASTINT (arg, lines / 2);
+   else
+     {
+       arg = Fprefix_numeric_value (arg);
+       if (XINT (arg) < 0)
+       XSETINT (arg, XINT (arg) + lines);
+     }
+ 
+   /* Skip past a partially visible first line.  */
+   if (w->vscroll)
+     XSETINT (arg, XINT (arg) + 1);
+ 
+   return Fvertical_motion (arg, window);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                        Window Configuration
+  ***********************************************************************/
+ 
+ struct save_window_data
+   {
+     EMACS_INT size_from_Lisp_Vector_struct;
+     struct Lisp_Vector *next_from_Lisp_Vector_struct;
+     Lisp_Object frame_cols, frame_lines, frame_menu_bar_lines;
+     Lisp_Object frame_tool_bar_lines;
+     Lisp_Object selected_frame;
+     Lisp_Object current_window;
+     Lisp_Object current_buffer;
+     Lisp_Object minibuf_scroll_window;
+     Lisp_Object minibuf_selected_window;
+     Lisp_Object root_window;
+     Lisp_Object focus_frame;
+     /* Record the values of window-min-width and window-min-height
+        so that window sizes remain consistent with them.  */
+     Lisp_Object min_width, min_height;
+     /* A vector, each of whose elements is a struct saved_window
+        for one window.  */
+     Lisp_Object saved_windows;
+   };
+ 
+ /* This is saved as a Lisp_Vector  */
+ struct saved_window
+ {
+   /* these first two must agree with struct Lisp_Vector in lisp.h */
+   EMACS_INT size_from_Lisp_Vector_struct;
+   struct Lisp_Vector *next_from_Lisp_Vector_struct;
+ 
+   Lisp_Object window;
+   Lisp_Object buffer, start, pointm, mark;
+   Lisp_Object left_col, top_line, total_cols, total_lines;
+   Lisp_Object hscroll, min_hscroll;
+   Lisp_Object parent, prev;
+   Lisp_Object start_at_line_beg;
+   Lisp_Object display_table;
+   Lisp_Object orig_top_line, orig_total_lines;
+   Lisp_Object left_margin_cols, right_margin_cols;
+   Lisp_Object left_fringe_width, right_fringe_width, fringes_outside_margins;
+   Lisp_Object scroll_bar_width, vertical_scroll_bar_type;
+ };
+ 
+ #define SAVED_WINDOW_VECTOR_SIZE 24 /* Arg to Fmake_vector */
+ 
+ #define SAVED_WINDOW_N(swv,n) \
+   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
+ 
+ DEFUN ("window-configuration-p", Fwindow_configuration_p, 
Swindow_configuration_p, 1, 1, 0,
+        doc: /* Return t if OBJECT is a window-configuration object.  */)
+      (object)
+      Lisp_Object object;
+ {
+   if (WINDOW_CONFIGURATIONP (object))
+     return Qt;
+   return Qnil;
+ }
+ 
+ DEFUN ("window-configuration-frame", Fwindow_configuration_frame, 
Swindow_configuration_frame, 1, 1, 0,
+        doc: /* Return the frame that CONFIG, a window-configuration object, 
is about.  */)
+      (config)
+      Lisp_Object config;
+ {
+   register struct save_window_data *data;
+   struct Lisp_Vector *saved_windows;
+ 
+   if (! WINDOW_CONFIGURATIONP (config))
+     wrong_type_argument (Qwindow_configuration_p, config);
+ 
+   data = (struct save_window_data *) XVECTOR (config);
+   saved_windows = XVECTOR (data->saved_windows);
+   return XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
+ }
+ 
+ DEFUN ("set-window-configuration", Fset_window_configuration,
+        Sset_window_configuration, 1, 1, 0,
+        doc: /* Set the configuration of windows and buffers as specified by 
CONFIGURATION.
+ CONFIGURATION must be a value previously returned
+ by `current-window-configuration' (which see).
+ If CONFIGURATION was made from a frame that is now deleted,
+ only frame-independent values can be restored.  In this case,
+ the return value is nil.  Otherwise the value is t.  */)
+      (configuration)
+      Lisp_Object configuration;
+ {
+   register struct save_window_data *data;
+   struct Lisp_Vector *saved_windows;
+   Lisp_Object new_current_buffer;
+   Lisp_Object frame;
+   FRAME_PTR f;
+   int old_point = -1;
+ 
+   while (!WINDOW_CONFIGURATIONP (configuration))
+     wrong_type_argument (Qwindow_configuration_p, configuration);
+ 
+   data = (struct save_window_data *) XVECTOR (configuration);
+   saved_windows = XVECTOR (data->saved_windows);
+ 
+   new_current_buffer = data->current_buffer;
+   if (NILP (XBUFFER (new_current_buffer)->name))
+     new_current_buffer = Qnil;
+   else
+     {
+       if (XBUFFER (new_current_buffer) == current_buffer)
+       old_point = PT;
+       else
+       old_point = BUF_PT (XBUFFER (new_current_buffer));
+     }
+ 
+   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
+   f = XFRAME (frame);
+ 
+   /* If f is a dead frame, don't bother rebuilding its window tree.
+      However, there is other stuff we should still try to do below.  */
+   if (FRAME_LIVE_P (f))
+     {
+       register struct window *w;
+       register struct saved_window *p;
+       struct window *root_window;
+       struct window **leaf_windows;
+       int n_leaf_windows;
+       int k, i, n;
+ 
+       /* If the frame has been resized since this window configuration was
+        made, we change the frame to the size specified in the
+        configuration, restore the configuration, and then resize it
+        back.  We keep track of the prevailing height in these variables.  */
+       int previous_frame_lines = FRAME_LINES (f);
+       int previous_frame_cols =  FRAME_COLS  (f);
+       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
+       int previous_frame_tool_bar_lines = FRAME_TOOL_BAR_LINES (f);
+ 
+       /* The mouse highlighting code could get screwed up
+        if it runs during this.  */
+       BLOCK_INPUT;
+ 
+       if (XFASTINT (data->frame_lines) != previous_frame_lines
+         || XFASTINT (data->frame_cols) != previous_frame_cols)
+       change_frame_size (f, XFASTINT (data->frame_lines),
+                          XFASTINT (data->frame_cols), 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_tool_bar_lines)
+         != previous_frame_tool_bar_lines)
+       x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
+ #endif
+ #endif
+ 
+       /* "Swap out" point from the selected window
+        into its buffer.  We do this now, before
+        restoring the window contents, and prevent it from
+        being done later on when we select a new window.  */
+       if (! NILP (XWINDOW (selected_window)->buffer))
+       {
+         w = XWINDOW (selected_window);
+         set_marker_both (w->pointm,
+                          w->buffer,
+                          BUF_PT (XBUFFER (w->buffer)),
+                          BUF_PT_BYTE (XBUFFER (w->buffer)));
+       }
+ 
+       windows_or_buffers_changed++;
+       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
+ 
+       /* Problem: Freeing all matrices and later allocating them again
+        is a serious redisplay flickering problem.  What we would
+        really like to do is to free only those matrices not reused
+        below.   */
+       root_window = XWINDOW (FRAME_ROOT_WINDOW (f));
+       leaf_windows
+       = (struct window **) alloca (count_windows (root_window)
+                                    * sizeof (struct window *));
+       n_leaf_windows = get_leaf_windows (root_window, leaf_windows, 0);
+ 
+       /* Temporarily avoid any problems with windows that are smaller
+        than they are supposed to be.  */
+       window_min_height = 1;
+       window_min_width = 1;
+ 
+       /* Kludge Alert!
+        Mark all windows now on frame as "deleted".
+        Restoring the new configuration "undeletes" any that are in it.
+ 
+        Save their current buffers in their height fields, since we may
+        need it later, if a buffer saved in the configuration is now
+        dead.  */
+       delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
+ 
+       for (k = 0; k < saved_windows->size; k++)
+       {
+         p = SAVED_WINDOW_N (saved_windows, k);
+         w = XWINDOW (p->window);
+         w->next = Qnil;
+ 
+         if (!NILP (p->parent))
+           w->parent = SAVED_WINDOW_N (saved_windows,
+                                       XFASTINT (p->parent))->window;
+         else
+           w->parent = Qnil;
+ 
+         if (!NILP (p->prev))
+           {
+             w->prev = SAVED_WINDOW_N (saved_windows,
+                                       XFASTINT (p->prev))->window;
+             XWINDOW (w->prev)->next = p->window;
+           }
+         else
+           {
+             w->prev = Qnil;
+             if (!NILP (w->parent))
+               {
+                 if (EQ (p->total_cols, XWINDOW (w->parent)->total_cols))
+                   {
+                     XWINDOW (w->parent)->vchild = p->window;
+                     XWINDOW (w->parent)->hchild = Qnil;
+                   }
+                 else
+                   {
+                     XWINDOW (w->parent)->hchild = p->window;
+                     XWINDOW (w->parent)->vchild = Qnil;
+                   }
+               }
+           }
+ 
+         /* If we squirreled away the buffer in the window's height,
+            restore it now.  */
+         if (BUFFERP (w->total_lines))
+           w->buffer = w->total_lines;
+         w->left_col = p->left_col;
+         w->top_line = p->top_line;
+         w->total_cols = p->total_cols;
+         w->total_lines = p->total_lines;
+         w->hscroll = p->hscroll;
+         w->min_hscroll = p->min_hscroll;
+         w->display_table = p->display_table;
+         w->orig_top_line = p->orig_top_line;
+         w->orig_total_lines = p->orig_total_lines;
+         w->left_margin_cols = p->left_margin_cols;
+         w->right_margin_cols = p->right_margin_cols;
+         w->left_fringe_width = p->left_fringe_width;
+         w->right_fringe_width = p->right_fringe_width;
+         w->fringes_outside_margins = p->fringes_outside_margins;
+         w->scroll_bar_width = p->scroll_bar_width;
+         w->vertical_scroll_bar_type = p->vertical_scroll_bar_type;
+         XSETFASTINT (w->last_modified, 0);
+         XSETFASTINT (w->last_overlay_modified, 0);
+ 
+         /* Reinstall the saved buffer and pointers into it.  */
+         if (NILP (p->buffer))
+           w->buffer = p->buffer;
+         else
+           {
+             if (!NILP (XBUFFER (p->buffer)->name))
+               /* If saved buffer is alive, install it.  */
+               {
+                 w->buffer = p->buffer;
+                 w->start_at_line_beg = p->start_at_line_beg;
+                 set_marker_restricted (w->start, p->start, w->buffer);
+                 set_marker_restricted (w->pointm, p->pointm, w->buffer);
+                 Fset_marker (XBUFFER (w->buffer)->mark,
+                              p->mark, w->buffer);
+ 
+                 /* As documented in Fcurrent_window_configuration, don't
+                    restore the location of point in the buffer which was
+                    current when the window configuration was recorded.  */
+                 if (!EQ (p->buffer, new_current_buffer)
+                     && XBUFFER (p->buffer) == current_buffer)
+                   Fgoto_char (w->pointm);
+               }
+             else if (NILP (w->buffer) || NILP (XBUFFER (w->buffer)->name))
+               /* Else unless window has a live buffer, get one.  */
+               {
+                 w->buffer = Fcdr (Fcar (Vbuffer_alist));
+                 /* This will set the markers to beginning of visible
+                    range.  */
+                 set_marker_restricted (w->start, make_number (0), w->buffer);
+                 set_marker_restricted (w->pointm, make_number (0),w->buffer);
+                 w->start_at_line_beg = Qt;
+               }
+             else
+               /* Keeping window's old buffer; make sure the markers
+                  are real.  */
+               {
+                 /* Set window markers at start of visible range.  */
+                 if (XMARKER (w->start)->buffer == 0)
+                   set_marker_restricted (w->start, make_number (0),
+                                          w->buffer);
+                 if (XMARKER (w->pointm)->buffer == 0)
+                   set_marker_restricted_both (w->pointm, w->buffer,
+                                               BUF_PT (XBUFFER (w->buffer)),
+                                               BUF_PT_BYTE (XBUFFER 
(w->buffer)));
+                 w->start_at_line_beg = Qt;
+               }
+           }
+       }
+ 
+       FRAME_ROOT_WINDOW (f) = data->root_window;
+       /* Prevent "swapping out point" in the old selected window
+        using the buffer that has been restored into it.
+        Use the point value from the beginning of this function
+        since unshow_buffer (called from delete_all_subwindows)
+        could have altered it.  */
+       selected_window = Qnil;
+       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer))
+       set_marker_restricted (XWINDOW (data->current_window)->pointm,
+                              make_number (old_point),
+                              XWINDOW (data->current_window)->buffer);
+ 
+       Fselect_window (data->current_window, Qnil);
+       XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
+       = selected_window;
+ 
+       if (NILP (data->focus_frame)
+         || (FRAMEP (data->focus_frame)
+             && FRAME_LIVE_P (XFRAME (data->focus_frame))))
+       Fredirect_frame_focus (frame, data->focus_frame);
+ 
+ #if 0 /* I don't understand why this is needed, and it causes problems
+          when the frame's old selected window has been deleted.  */
+       if (f != selected_frame && FRAME_WINDOW_P (f))
+       do_switch_frame (WINDOW_FRAME (XWINDOW (data->root_window)),
+                        0, 0);
+ #endif
+ 
+       /* Set the screen height to the value it had before this function.  */
+       if (previous_frame_lines != FRAME_LINES (f)
+         || previous_frame_cols != FRAME_COLS (f))
+       change_frame_size (f, previous_frame_lines, previous_frame_cols,
+                          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_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
+ 
+       /* Now, free glyph matrices in windows that were not reused.  */
+       for (i = n = 0; i < n_leaf_windows; ++i)
+       {
+         if (NILP (leaf_windows[i]->buffer))
+           {
+             /* Assert it's not reused as a combination.  */
+             xassert (NILP (leaf_windows[i]->hchild)
+                      && NILP (leaf_windows[i]->vchild));
+             free_window_matrices (leaf_windows[i]);
+           }
+         else if (EQ (leaf_windows[i]->buffer, new_current_buffer))
+           ++n;
+       }
+ 
+       adjust_glyphs (f);
+ 
+       UNBLOCK_INPUT;
+ 
+       /* Fselect_window will have made f the selected frame, so we
+        reselect the proper frame here.  Fhandle_switch_frame will change the
+        selected window too, but that doesn't make the call to
+        Fselect_window above totally superfluous; it still sets f's
+        selected window.  */
+       if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
+       do_switch_frame (data->selected_frame, 0, 0);
+ 
+       if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+     }
+ 
+   if (!NILP (new_current_buffer))
+     Fset_buffer (new_current_buffer);
+ 
+   /* Restore the minimum heights recorded in the configuration.  */
+   window_min_height = XINT (data->min_height);
+   window_min_width = XINT (data->min_width);
+ 
+   Vminibuf_scroll_window = data->minibuf_scroll_window;
+   minibuf_selected_window = data->minibuf_selected_window;
+ 
+   return (FRAME_LIVE_P (f) ? Qt : Qnil);
+ }
+ 
+ /* Mark all windows now on frame as deleted
+    by setting their buffers to nil.  */
+ 
+ void
+ delete_all_subwindows (w)
+      register struct window *w;
+ {
+   if (!NILP (w->next))
+     delete_all_subwindows (XWINDOW (w->next));
+   if (!NILP (w->vchild))
+     delete_all_subwindows (XWINDOW (w->vchild));
+   if (!NILP (w->hchild))
+     delete_all_subwindows (XWINDOW (w->hchild));
+ 
+   w->total_lines = w->buffer;       /* See Fset_window_configuration for 
excuse.  */
+ 
+   if (!NILP (w->buffer))
+     unshow_buffer (w);
+ 
+   /* We set all three of these fields to nil, to make sure that we can
+      distinguish this dead window from any live window.  Live leaf
+      windows will have buffer set, and combination windows will have
+      vchild or hchild set.  */
+   w->buffer = Qnil;
+   w->vchild = Qnil;
+   w->hchild = Qnil;
+ 
+   Vwindow_list = Qnil;
+ }
+ 
+ static int
+ count_windows (window)
+      register struct window *window;
+ {
+   register int count = 1;
+   if (!NILP (window->next))
+     count += count_windows (XWINDOW (window->next));
+   if (!NILP (window->vchild))
+     count += count_windows (XWINDOW (window->vchild));
+   if (!NILP (window->hchild))
+     count += count_windows (XWINDOW (window->hchild));
+   return count;
+ }
+ 
+ 
+ /* Fill vector FLAT with leaf windows under W, starting at index I.
+    Value is last index + 1.  */
+ 
+ static int
+ get_leaf_windows (w, flat, i)
+      struct window *w;
+      struct window **flat;
+      int i;
+ {
+   while (w)
+     {
+       if (!NILP (w->hchild))
+       i = get_leaf_windows (XWINDOW (w->hchild), flat, i);
+       else if (!NILP (w->vchild))
+       i = get_leaf_windows (XWINDOW (w->vchild), flat, i);
+       else
+       flat[i++] = w;
+ 
+       w = NILP (w->next) ? 0 : XWINDOW (w->next);
+     }
+ 
+   return i;
+ }
+ 
+ 
+ /* Return a pointer to the glyph W's physical cursor is on.  Value is
+    null if W's current matrix is invalid, so that no meaningfull glyph
+    can be returned.  */
+ 
+ struct glyph *
+ get_phys_cursor_glyph (w)
+      struct window *w;
+ {
+   struct glyph_row *row;
+   struct glyph *glyph;
+ 
+   if (w->phys_cursor.vpos >= 0
+       && w->phys_cursor.vpos < w->current_matrix->nrows
+       && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
+         row->enabled_p)
+       && row->used[TEXT_AREA] > w->phys_cursor.hpos)
+     glyph = row->glyphs[TEXT_AREA] + w->phys_cursor.hpos;
+   else
+     glyph = NULL;
+ 
+   return glyph;
+ }
+ 
+ 
+ static int
+ save_window_save (window, vector, i)
+      Lisp_Object window;
+      struct Lisp_Vector *vector;
+      int i;
+ {
+   register struct saved_window *p;
+   register struct window *w;
+   register Lisp_Object tem;
+ 
+   for (;!NILP (window); window = w->next)
+     {
+       p = SAVED_WINDOW_N (vector, i);
+       w = XWINDOW (window);
+ 
+       XSETFASTINT (w->temslot, i++);
+       p->window = window;
+       p->buffer = w->buffer;
+       p->left_col = w->left_col;
+       p->top_line = w->top_line;
+       p->total_cols = w->total_cols;
+       p->total_lines = w->total_lines;
+       p->hscroll = w->hscroll;
+       p->min_hscroll = w->min_hscroll;
+       p->display_table = w->display_table;
+       p->orig_top_line = w->orig_top_line;
+       p->orig_total_lines = w->orig_total_lines;
+       p->left_margin_cols = w->left_margin_cols;
+       p->right_margin_cols = w->right_margin_cols;
+       p->left_fringe_width = w->left_fringe_width;
+       p->right_fringe_width = w->right_fringe_width;
+       p->fringes_outside_margins = w->fringes_outside_margins;
+       p->scroll_bar_width = w->scroll_bar_width;
+       p->vertical_scroll_bar_type = w->vertical_scroll_bar_type;
+       if (!NILP (w->buffer))
+       {
+         /* Save w's value of point in the window configuration.
+            If w is the selected window, then get the value of point
+            from the buffer; pointm is garbage in the selected window.  */
+         if (EQ (window, selected_window))
+           {
+             p->pointm = Fmake_marker ();
+             set_marker_both (p->pointm, w->buffer,
+                              BUF_PT (XBUFFER (w->buffer)),
+                              BUF_PT_BYTE (XBUFFER (w->buffer)));
+           }
+         else
+           p->pointm = Fcopy_marker (w->pointm, Qnil);
+ 
+         p->start = Fcopy_marker (w->start, Qnil);
+         p->start_at_line_beg = w->start_at_line_beg;
+ 
+         tem = XBUFFER (w->buffer)->mark;
+         p->mark = Fcopy_marker (tem, Qnil);
+       }
+       else
+       {
+         p->pointm = Qnil;
+         p->start = Qnil;
+         p->mark = Qnil;
+         p->start_at_line_beg = Qnil;
+       }
+ 
+       if (NILP (w->parent))
+       p->parent = Qnil;
+       else
+       p->parent = XWINDOW (w->parent)->temslot;
+ 
+       if (NILP (w->prev))
+       p->prev = Qnil;
+       else
+       p->prev = XWINDOW (w->prev)->temslot;
+ 
+       if (!NILP (w->vchild))
+       i = save_window_save (w->vchild, vector, i);
+       if (!NILP (w->hchild))
+       i = save_window_save (w->hchild, vector, i);
+     }
+ 
+   return i;
+ }
+ 
+ DEFUN ("current-window-configuration", Fcurrent_window_configuration,
+        Scurrent_window_configuration, 0, 1, 0,
+        doc: /* Return an object representing the current window configuration 
of FRAME.
+ If FRAME is nil or omitted, use the selected frame.
+ This describes the number of windows, their sizes and current buffers,
+ and for each displayed buffer, where display starts, and the positions of
+ point and mark.  An exception is made for point in the current buffer:
+ its value is -not- saved.
+ This also records the currently selected frame, and FRAME's focus
+ redirection (see `redirect-frame-focus').  */)
+      (frame)
+      Lisp_Object frame;
+ {
+   register Lisp_Object tem;
+   register int n_windows;
+   register struct save_window_data *data;
+   register struct Lisp_Vector *vec;
+   register int i;
+   FRAME_PTR f;
+ 
+   if (NILP (frame))
+     frame = selected_frame;
+   CHECK_LIVE_FRAME (frame);
+   f = XFRAME (frame);
+ 
+   n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
+   vec = allocate_other_vector (VECSIZE (struct save_window_data));
+   data = (struct save_window_data *)vec;
+ 
+   XSETFASTINT (data->frame_cols, FRAME_COLS (f));
+   XSETFASTINT (data->frame_lines, FRAME_LINES (f));
+   XSETFASTINT (data->frame_menu_bar_lines, FRAME_MENU_BAR_LINES (f));
+   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 = minibuf_level > 0 ? Vminibuf_scroll_window : 
Qnil;
+   data->minibuf_selected_window = minibuf_level > 0 ? minibuf_selected_window 
: Qnil;
+   data->root_window = FRAME_ROOT_WINDOW (f);
+   data->focus_frame = FRAME_FOCUS_FRAME (f);
+   XSETINT (data->min_height, window_min_height);
+   XSETINT (data->min_width, window_min_width);
+   tem = Fmake_vector (make_number (n_windows), Qnil);
+   data->saved_windows = tem;
+   for (i = 0; i < n_windows; i++)
+     XVECTOR (tem)->contents[i]
+       = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil);
+   save_window_save (FRAME_ROOT_WINDOW (f), XVECTOR (tem), 0);
+   XSETWINDOW_CONFIGURATION (tem, data);
+   return (tem);
+ }
+ 
+ DEFUN ("save-window-excursion", Fsave_window_excursion, 
Ssave_window_excursion,
+        0, UNEVALLED, 0,
+        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.
+ Also restore which buffer is current.
+ Does not restore the value of point in current buffer.
+ usage: (save-window-excursion BODY ...)  */)
+      (args)
+      Lisp_Object args;
+ {
+   register Lisp_Object val;
+   register int count = SPECPDL_INDEX ();
+ 
+   record_unwind_protect (Fset_window_configuration,
+                        Fcurrent_window_configuration (Qnil));
+   val = Fprogn (args);
+   return unbind_to (count, val);
+ }
+ 
+ 
+ /***********************************************************************
+                           Marginal Areas
+  ***********************************************************************/
+ 
+ DEFUN ("set-window-margins", Fset_window_margins, Sset_window_margins,
+        2, 3, 0,
+        doc: /* Set width of marginal areas of window WINDOW.
+ If WINDOW is nil, set margins of the currently selected window.
+ Second arg LEFT-WIDTH specifies the number of character cells to
+ reserve for the left marginal area.  Optional third arg RIGHT-WIDTH
+ does the same for the right marginal area.  A nil width parameter
+ means no margin.  */)
+      (window, left, right)
+      Lisp_Object window, left, right;
+ {
+   struct window *w = decode_window (window);
+ 
+   /* Translate negative or zero widths to nil.
+      Margins that are too wide have to be checked elsewhere.  */
+ 
+   if (!NILP (left))
+     {
+       CHECK_NUMBER (left);
+       if (XINT (left) <= 0)
+       left = Qnil;
+     }
+ 
+   if (!NILP (right))
+     {
+       CHECK_NUMBER (right);
+       if (XINT (right) <= 0)
+       right = Qnil;
+     }
+ 
+   if (!EQ (w->left_margin_cols, left)
+       || !EQ (w->right_margin_cols, right))
+     {
+       w->left_margin_cols = left;
+       w->right_margin_cols = right;
+ 
+       adjust_window_margins (w);
+ 
+       ++windows_or_buffers_changed;
+       adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+     }
+ 
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("window-margins", Fwindow_margins, Swindow_margins,
+        0, 1, 0,
+        doc: /* Get width of marginal areas of window WINDOW.
+ If WINDOW is omitted or nil, use the currently selected window.
+ Value is a cons of the form (LEFT-WIDTH . RIGHT-WIDTH).
+ If a marginal area does not exist, its width will be returned
+ as nil.  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w = decode_window (window);
+   return Fcons (w->left_margin_cols, w->right_margin_cols);
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           Fringes
+  ***********************************************************************/
+ 
+ DEFUN ("set-window-fringes", Fset_window_fringes, Sset_window_fringes,
+        2, 4, 0,
+        doc: /* Set the fringe widths of window WINDOW.
+ If WINDOW is nil, set the fringe widths of the currently selected
+ window.
+ Second arg LEFT-WIDTH specifies the number of pixels to reserve for
+ the left fringe.  Optional third arg RIGHT-WIDTH specifies the right
+ fringe width.  If a fringe width arg is nil, that means to use the
+ frame's default fringe width.  Default fringe widths can be set with
+ the command `set-fringe-style'.
+ If optional fourth arg OUTSIDE-MARGINS is non-nil, draw the fringes
+ outside of the display margins.  By default, fringes are drawn between
+ display marginal areas and the text area.  */)
+      (window, left, right, outside_margins)
+      Lisp_Object window, left, right, outside_margins;
+ {
+   struct window *w = decode_window (window);
+ 
+   if (!NILP (left))
+     CHECK_NUMBER (left);
+   if (!NILP (right))
+     CHECK_NUMBER (right);
+ 
+   if (!EQ (w->left_fringe_width, left)
+       || !EQ (w->right_fringe_width, right)
+       || !EQ (w->fringes_outside_margins, outside_margins))
+     {
+       w->left_fringe_width = left;
+       w->right_fringe_width = right;
+       w->fringes_outside_margins = outside_margins;
+ 
+       adjust_window_margins (w);
+ 
+       clear_glyph_matrix (w->current_matrix);
+       w->window_end_valid = Qnil;
+ 
+       ++windows_or_buffers_changed;
+       adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+     }
+ 
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("window-fringes", Fwindow_fringes, Swindow_fringes,
+        0, 1, 0,
+        doc: /* Get width of fringes of window WINDOW.
+ If WINDOW is omitted or nil, use the currently selected window.
+ Value is a list of the form (LEFT-WIDTH RIGHT-WIDTH OUTSIDE-MARGINS).  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w = decode_window (window);
+   return Fcons (make_number (WINDOW_LEFT_FRINGE_WIDTH (w)),
+               Fcons (make_number (WINDOW_RIGHT_FRINGE_WIDTH (w)),
+                      Fcons ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ?
+                              Qt : Qnil), Qnil)));
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                           Scroll bars
+  ***********************************************************************/
+ 
+ DEFUN ("set-window-scroll-bars", Fset_window_scroll_bars, 
Sset_window_scroll_bars,
+        2, 4, 0,
+        doc: /* Set width and type of scroll bars of window WINDOW.
+ If window is nil, set scroll bars of the currently selected window.
+ Second parameter WIDTH specifies the pixel width for the scroll bar;
+ this is automatically adjusted to a multiple of the frame column width.
+ Third parameter VERTICAL-TYPE specifies the type of the vertical scroll
+ bar: left, right, or nil.
+ If WIDTH is nil, use the frame's scroll-bar width.
+ If TYPE is t, use the frame's scroll-bar type.  */)
+      (window, width, vertical_type, horizontal_type)
+      Lisp_Object window, width, vertical_type, horizontal_type;
+ {
+   struct window *w = decode_window (window);
+ 
+   if (!NILP (width))
+     CHECK_NUMBER (width);
+ 
+   if (XINT (width) == 0)
+     vertical_type = Qnil;
+ 
+   if (!(EQ (vertical_type, Qnil)
+       || EQ (vertical_type, Qleft)
+       || EQ (vertical_type, Qright)
+       || EQ (vertical_type, Qt)))
+     error ("Invalid type of vertical scroll bar");
+ 
+   if (!EQ (w->scroll_bar_width, width)
+       || !EQ (w->vertical_scroll_bar_type, vertical_type))
+     {
+       w->scroll_bar_width = width;
+       w->vertical_scroll_bar_type = vertical_type;
+ 
+       adjust_window_margins (w);
+ 
+       clear_glyph_matrix (w->current_matrix);
+       w->window_end_valid = Qnil;
+ 
+       ++windows_or_buffers_changed;
+       adjust_glyphs (XFRAME (WINDOW_FRAME (w)));
+     }
+ 
+   return Qnil;
+ }
+ 
+ 
+ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars,
+        0, 1, 0,
+        doc: /* Get width and type of scroll bars of window WINDOW.
+ If WINDOW is omitted or nil, use the currently selected window.
+ Value is a list of the form (WIDTH COLS VERTICAL-TYPE HORIZONTAL-TYPE).
+ If WIDTH is nil or TYPE is t, the window is using the frame's corresponding
+ value.  */)
+      (window)
+      Lisp_Object window;
+ {
+   struct window *w = decode_window (window);
+   return Fcons (make_number ((WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
+                             ? WINDOW_CONFIG_SCROLL_BAR_WIDTH (w)
+                             : WINDOW_SCROLL_BAR_AREA_WIDTH (w))),
+               Fcons (make_number (WINDOW_SCROLL_BAR_COLS (w)),
+                      Fcons (w->vertical_scroll_bar_type,
+                             Fcons (Qnil, Qnil))));
+ }
+ 
+ 
+ 
+ /***********************************************************************
+                          Smooth scrolling
+  ***********************************************************************/
+ 
+ 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.
+ 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;
+   struct window *w;
+ 
+   if (NILP (window))
+     window = selected_window;
+   else
+     CHECK_WINDOW (window);
+   w = XWINDOW (window);
+   f = XFRAME (w->frame);
+ 
+   if (FRAME_WINDOW_P (f))
+     result = (NILP (pixels_p)
+             ? FRAME_CANON_Y_FROM_PIXEL_Y (f, -w->vscroll)
+             : make_number (-w->vscroll));
+   else
+     result = make_number (0);
+   return result;
+ }
+ 
+ 
+ DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
+        2, 3, 0,
+        doc: /* Set amount by which WINDOW should be scrolled vertically to 
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;
+ 
+   if (NILP (window))
+     window = selected_window;
+   else
+     CHECK_WINDOW (window);
+   CHECK_NUMBER_OR_FLOAT (vscroll);
+ 
+   w = XWINDOW (window);
+   f = XFRAME (w->frame);
+ 
+   if (FRAME_WINDOW_P (f))
+     {
+       int old_dy = w->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
+        area becomes larger than before.  */
+       if (w->vscroll < 0 && w->vscroll < old_dy)
+       adjust_glyphs (f);
+ 
+       /* Prevent redisplay shortcuts.  */
+       XBUFFER (w->buffer)->prevent_redisplay_optimizations_p = 1;
+     }
+ 
+   return Fwindow_vscroll (window, pixels_p);
+ }
+ 
+ 
+ /* 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 argument USER_DATA.  Stops when FN returns 0.  */
+ 
+ void
+ foreach_window (f, fn, user_data)
+      struct frame *f;
+      int (* fn) P_ ((struct window *, void *));
+      void *user_data;
+ {
+   foreach_window_1 (XWINDOW (FRAME_ROOT_WINDOW (f)), fn, user_data);
+ }
+ 
+ 
+ /* 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 argument USER_DATA.
+    Stop when FN returns 0.  Value is 0 if stopped by FN.  */
+ 
+ static int
+ foreach_window_1 (w, fn, user_data)
+      struct window *w;
+      int (* fn) P_ ((struct window *, void *));
+      void *user_data;
+ {
+   int cont;
+ 
+   for (cont = 1; w && cont;)
+     {
+       if (!NILP (w->hchild))
+       cont = foreach_window_1 (XWINDOW (w->hchild), fn, user_data);
+       else if (!NILP (w->vchild))
+       cont = foreach_window_1 (XWINDOW (w->vchild), fn, user_data);
+       else
+       cont = fn (w, user_data);
+ 
+       w = NILP (w->next) ? 0 : XWINDOW (w->next);
+     }
+ 
+   return cont;
+ }
+ 
+ 
+ /* Freeze or unfreeze the window start of W unless it is a
+    mini-window or the selected window.  FREEZE_P non-null means freeze
+    the window start.  */
+ 
+ static int
+ freeze_window_start (w, freeze_p)
+      struct window *w;
+      void *freeze_p;
+ {
+   if (w == XWINDOW (selected_window)
+       || MINI_WINDOW_P (w)
+       || (MINI_WINDOW_P (XWINDOW (selected_window))
+         && ! NILP (Vminibuf_scroll_window)
+         && w == XWINDOW (Vminibuf_scroll_window)))
+     freeze_p = NULL;
+ 
+   w->frozen_window_start_p = freeze_p != NULL;
+   return 1;
+ }
+ 
+ 
+ /* 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, (void *) (freeze_p ? f : 0));
+ }
+ 
+ 
+ /***********************************************************************
+                           Initialization
+  ***********************************************************************/
+ 
+ /* Return 1 if window configurations C1 and C2
+    describe the same state of affairs.  This is used by Fequal.   */
+ 
+ int
+ compare_window_configurations (c1, c2, ignore_positions)
+      Lisp_Object c1, c2;
+      int ignore_positions;
+ {
+   register struct save_window_data *d1, *d2;
+   struct Lisp_Vector *sw1, *sw2;
+   int i;
+ 
+   if (!WINDOW_CONFIGURATIONP (c1))
+     wrong_type_argument (Qwindow_configuration_p, c1);
+   if (!WINDOW_CONFIGURATIONP (c2))
+     wrong_type_argument (Qwindow_configuration_p, c2);
+ 
+   d1 = (struct save_window_data *) XVECTOR (c1);
+   d2 = (struct save_window_data *) XVECTOR (c2);
+   sw1 = XVECTOR (d1->saved_windows);
+   sw2 = XVECTOR (d2->saved_windows);
+ 
+   if (! EQ (d1->frame_cols, d2->frame_cols))
+     return 0;
+   if (! EQ (d1->frame_lines, d2->frame_lines))
+     return 0;
+   if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
+     return 0;
+   if (! EQ (d1->selected_frame, d2->selected_frame))
+     return 0;
+   /* Don't compare the current_window field directly.
+      Instead see w1_is_current and w2_is_current, below.  */
+   if (! EQ (d1->current_buffer, d2->current_buffer))
+     return 0;
+   if (! ignore_positions)
+     {
+       if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
+       return 0;
+       if (! EQ (d1->minibuf_selected_window, d2->minibuf_selected_window))
+       return 0;
+     }
+   /* Don't compare the root_window field.
+      We don't require the two configurations
+      to use the same window object,
+      and the two root windows must be equivalent
+      if everything else compares equal.  */
+   if (! EQ (d1->focus_frame, d2->focus_frame))
+     return 0;
+   if (! EQ (d1->min_width, d2->min_width))
+     return 0;
+   if (! EQ (d1->min_height, d2->min_height))
+     return 0;
+ 
+   /* Verify that the two confis have the same number of windows.  */
+   if (sw1->size != sw2->size)
+     return 0;
+ 
+   for (i = 0; i < sw1->size; i++)
+     {
+       struct saved_window *p1, *p2;
+       int w1_is_current, w2_is_current;
+ 
+       p1 = SAVED_WINDOW_N (sw1, i);
+       p2 = SAVED_WINDOW_N (sw2, i);
+ 
+       /* Verify that the current windows in the two
+        configurations correspond to each other.  */
+       w1_is_current = EQ (d1->current_window, p1->window);
+       w2_is_current = EQ (d2->current_window, p2->window);
+ 
+       if (w1_is_current != w2_is_current)
+       return 0;
+ 
+       /* Verify that the corresponding windows do match.  */
+       if (! EQ (p1->buffer, p2->buffer))
+       return 0;
+       if (! EQ (p1->left_col, p2->left_col))
+       return 0;
+       if (! EQ (p1->top_line, p2->top_line))
+       return 0;
+       if (! EQ (p1->total_cols, p2->total_cols))
+       return 0;
+       if (! EQ (p1->total_lines, p2->total_lines))
+       return 0;
+       if (! EQ (p1->display_table, p2->display_table))
+       return 0;
+       if (! EQ (p1->parent, p2->parent))
+       return 0;
+       if (! EQ (p1->prev, p2->prev))
+       return 0;
+       if (! ignore_positions)
+       {
+         if (! EQ (p1->hscroll, p2->hscroll))
+           return 0;
+         if (!EQ (p1->min_hscroll, p2->min_hscroll))
+           return 0;
+         if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
+           return 0;
+         if (NILP (Fequal (p1->start, p2->start)))
+           return 0;
+         if (NILP (Fequal (p1->pointm, p2->pointm)))
+           return 0;
+         if (NILP (Fequal (p1->mark, p2->mark)))
+           return 0;
+       }
+       if (! EQ (p1->left_margin_cols, p2->left_margin_cols))
+       return 0;
+       if (! EQ (p1->right_margin_cols, p2->right_margin_cols))
+       return 0;
+       if (! EQ (p1->left_fringe_width, p2->left_fringe_width))
+       return 0;
+       if (! EQ (p1->right_fringe_width, p2->right_fringe_width))
+       return 0;
+       if (! EQ (p1->fringes_outside_margins, p2->fringes_outside_margins))
+       return 0;
+       if (! EQ (p1->scroll_bar_width, p2->scroll_bar_width))
+       return 0;
+       if (! EQ (p1->vertical_scroll_bar_type, p2->vertical_scroll_bar_type))
+       return 0;
+     }
+ 
+   return 1;
+ }
+ 
+ DEFUN ("compare-window-configurations", Fcompare_window_configurations,
+        Scompare_window_configurations, 2, 2, 0,
+        doc: /* Compare two window configurations as regards the structure of 
windows.
+ This function ignores details such as the values of point and mark
+ and scrolling positions.  */)
+      (x, y)
+      Lisp_Object x, y;
+ {
+   if (compare_window_configurations (x, y, 1))
+     return Qt;
+   return Qnil;
+ }
+ 
+ void
+ init_window_once ()
+ {
+   struct frame *f = make_terminal_frame ();
+   XSETFRAME (selected_frame, f);
+   Vterminal_frame = selected_frame;
+   minibuf_window = f->minibuffer_window;
+   selected_window = f->selected_window;
+   last_nonminibuf_frame = f;
+ 
+   window_initialized = 1;
+ }
+ 
+ void
+ init_window ()
+ {
+   Vwindow_list = Qnil;
+ }
+ 
+ void
+ syms_of_window ()
+ {
+   Qwindow_size_fixed = intern ("window-size-fixed");
+   staticpro (&Qwindow_size_fixed);
+ 
+   staticpro (&Qwindow_configuration_change_hook);
+   Qwindow_configuration_change_hook
+     = intern ("window-configuration-change-hook");
+ 
+   Qwindowp = intern ("windowp");
+   staticpro (&Qwindowp);
+ 
+   Qwindow_configuration_p = intern ("window-configuration-p");
+   staticpro (&Qwindow_configuration_p);
+ 
+   Qwindow_live_p = intern ("window-live-p");
+   staticpro (&Qwindow_live_p);
+ 
+   Qtemp_buffer_show_hook = intern ("temp-buffer-show-hook");
+   staticpro (&Qtemp_buffer_show_hook);
+ 
+   staticpro (&Vwindow_list);
+ 
+   minibuf_selected_window = Qnil;
+   staticpro (&minibuf_selected_window);
+ 
+   DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function,
+              doc: /* Non-nil means call as function to display a help buffer.
+ The function is called with one argument, the buffer to be displayed.
+ Used by `with-output-to-temp-buffer'.
+ If this function is used, then it must do the entire job of showing
+ the buffer; `temp-buffer-show-hook' is not run unless this function runs it.  
*/);
+   Vtemp_buffer_show_function = Qnil;
+ 
+   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.
+ 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;
+ 
+   DEFVAR_LISP ("even-window-heights", &Veven_window_heights,
+              doc: /* *If non-nil, `display-buffer' should even the window 
heights.
+ If nil, `display-buffer' will leave the window configuration alone.  */);
+   Veven_window_heights = Qt;
+ 
+   DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window,
+              doc: /* Non-nil means it is the window that C-M-v in minibuffer 
should scroll.  */);
+   Vminibuf_scroll_window = Qnil;
+ 
+   DEFVAR_BOOL ("mode-line-in-non-selected-windows", 
&mode_line_in_non_selected_windows,
+              doc: /* Non-nil means to use `mode-line-inactive' face in 
non-selected windows.
+ If the minibuffer is active, the `minibuffer-scroll-window' mode line
+ is displayed in the `mode-line' face.  */);
+   mode_line_in_non_selected_windows = 1;
+ 
+   DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer,
+              doc: /* If non-nil, this is a buffer and \\[scroll-other-window] 
should scroll its window.  */);
+   Vother_window_scroll_buffer = Qnil;
+ 
+   DEFVAR_BOOL ("pop-up-frames", &pop_up_frames,
+              doc: /* *Non-nil means `display-buffer' should make a separate 
frame.  */);
+   pop_up_frames = 0;
+ 
+   DEFVAR_BOOL ("display-buffer-reuse-frames", &display_buffer_reuse_frames,
+              doc: /* *Non-nil means `display-buffer' should reuse frames.
+ If the buffer in question is already displayed in a frame, raise that frame.  
*/);
+   display_buffer_reuse_frames = 0;
+ 
+   DEFVAR_LISP ("pop-up-frame-function", &Vpop_up_frame_function,
+              doc: /* Function to call to handle automatic new frame creation.
+ It is called with no arguments and should return a newly created frame.
+ 
+ A typical value might be `(lambda () (new-frame pop-up-frame-alist))'
+ where `pop-up-frame-alist' would hold the default frame parameters.  */);
+   Vpop_up_frame_function = Qnil;
+ 
+   DEFVAR_LISP ("special-display-buffer-names", &Vspecial_display_buffer_names,
+              doc: /* *List of buffer names that should have their own special 
frames.
+ Displaying a buffer whose name is in this list makes a special frame for it
+ 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, 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
+ buffer is displayed in the currently selected window.  Otherwise, if
+ they include (same-frame . t), the buffer is displayed in a new window
+ in the currently selected frame.
+ 
+ If this variable appears \"not to work\", because you add a name to it
+ but that buffer still appears in the selected window, look at the
+ values of `same-window-buffer-names' and `same-window-regexps'.
+ Those variables take precedence over this one.  */);
+   Vspecial_display_buffer_names = Qnil;
+ 
+   DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
+              doc: /* *List of regexps saying which buffers should have their 
own special frames.
+ If a buffer name matches one of these regexps, it gets its own frame.
+ Displaying a buffer whose name is in this list makes a special frame for it
+ 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, 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
+ buffer is displayed in the currently selected window.  Otherwise, if
+ they include (same-frame . t), the buffer is displayed in a new window
+ in the currently selected frame.
+ 
+ If this variable appears \"not to work\", because you add a regexp to it
+ but the matching buffers still appear in the selected window, look at the
+ values of `same-window-buffer-names' and `same-window-regexps'.
+ Those variables take precedence over this one.  */);
+   Vspecial_display_regexps = Qnil;
+ 
+   DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
+              doc: /* Function to call to make a new frame for a special 
buffer.
+ It is called with two arguments, the buffer and optional buffer specific
+ data, and should return a window displaying that buffer.
+ The default value normally makes a separate frame for the buffer,
+   using `special-display-frame-alist' to specify the frame parameters.
+ But if the buffer specific data includes (same-buffer . t) then the
+   buffer is displayed in the current selected window.
+ Otherwise if it includes (same-frame . t) then the buffer is displayed in
+   a new window in the currently selected frame.
+ 
+ A buffer is special if it is listed in `special-display-buffer-names'
+ or matches a regexp in `special-display-regexps'.  */);
+   Vspecial_display_function = Qnil;
+ 
+   DEFVAR_LISP ("same-window-buffer-names", &Vsame_window_buffer_names,
+              doc: /* *List of buffer names that should appear in the selected 
window.
+ Displaying one of these buffers using `display-buffer' or `pop-to-buffer'
+ switches to it in the selected window, rather than making it appear
+ in some other window.
+ 
+ An element of the list can be a cons cell instead of just a string.
+ Then the car must be a string, which specifies the buffer name.
+ This is for compatibility with `special-display-buffer-names';
+ the cdr of the cons cell is ignored.
+ 
+ See also `same-window-regexps'.  */);
+   Vsame_window_buffer_names = Qnil;
+ 
+   DEFVAR_LISP ("same-window-regexps", &Vsame_window_regexps,
+              doc: /* *List of regexps saying which buffers should appear in 
the selected window.
+ If a buffer name matches one of these regexps, then displaying it
+ using `display-buffer' or `pop-to-buffer' switches to it
+ in the selected window, rather than making it appear in some other window.
+ 
+ An element of the list can be a cons cell instead of just a string.
+ Then the car must be a string, which specifies the buffer name.
+ This is for compatibility with `special-display-buffer-names';
+ the cdr of the cons cell is ignored.
+ 
+ See also `same-window-buffer-names'.  */);
+   Vsame_window_regexps = Qnil;
+ 
+   DEFVAR_BOOL ("pop-up-windows", &pop_up_windows,
+              doc: /* *Non-nil means display-buffer should make new windows.  
*/);
+   pop_up_windows = 1;
+ 
+   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines,
+             doc: /* *Number of lines of continuity when scrolling by 
screenfuls.  */);
+   next_screen_context_lines = 2;
+ 
+   DEFVAR_INT ("split-height-threshold", &split_height_threshold,
+             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;
+ 
+   DEFVAR_INT ("window-min-height", &window_min_height,
+             doc: /* *Delete any window less than this tall (including its 
mode line).  */);
+   window_min_height = 4;
+ 
+   DEFVAR_INT ("window-min-width", &window_min_width,
+             doc: /* *Delete any window less than this wide.  */);
+   window_min_width = 10;
+ 
+   DEFVAR_LISP ("scroll-preserve-screen-position",
+              &Vscroll_preserve_screen_position,
+              doc: /* *Non-nil means scroll commands move point to keep its 
screen line unchanged.  */);
+   Vscroll_preserve_screen_position = Qnil;
+ 
+   DEFVAR_LISP ("window-configuration-change-hook",
+              &Vwindow_configuration_change_hook,
+              doc: /* Functions to call when window configuration changes.
+ The selected frame is the one whose configuration has changed.  */);
+   Vwindow_configuration_change_hook = Qnil;
+ 
+   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.  */);
+   Fmake_variable_buffer_local (Qwindow_size_fixed);
+   window_size_fixed = 0;
+ 
+   defsubr (&Sselected_window);
+   defsubr (&Sminibuffer_window);
+   defsubr (&Swindow_minibuffer_p);
+   defsubr (&Swindowp);
+   defsubr (&Swindow_live_p);
+   defsubr (&Spos_visible_in_window_p);
+   defsubr (&Swindow_buffer);
+   defsubr (&Swindow_height);
+   defsubr (&Swindow_width);
+   defsubr (&Swindow_hscroll);
+   defsubr (&Sset_window_hscroll);
+   defsubr (&Swindow_redisplay_end_trigger);
+   defsubr (&Sset_window_redisplay_end_trigger);
+   defsubr (&Swindow_edges);
+   defsubr (&Swindow_pixel_edges);
+   defsubr (&Swindow_inside_edges);
+   defsubr (&Swindow_inside_pixel_edges);
+   defsubr (&Scoordinates_in_window_p);
+   defsubr (&Swindow_at);
+   defsubr (&Swindow_point);
+   defsubr (&Swindow_start);
+   defsubr (&Swindow_end);
+   defsubr (&Sset_window_point);
+   defsubr (&Sset_window_start);
+   defsubr (&Swindow_dedicated_p);
+   defsubr (&Sset_window_dedicated_p);
+   defsubr (&Swindow_display_table);
+   defsubr (&Sset_window_display_table);
+   defsubr (&Snext_window);
+   defsubr (&Sprevious_window);
+   defsubr (&Sother_window);
+   defsubr (&Sget_lru_window);
+   defsubr (&Sget_largest_window);
+   defsubr (&Sget_buffer_window);
+   defsubr (&Sdelete_other_windows);
+   defsubr (&Sdelete_windows_on);
+   defsubr (&Sreplace_buffer_in_windows);
+   defsubr (&Sdelete_window);
+   defsubr (&Sset_window_buffer);
+   defsubr (&Sselect_window);
+   defsubr (&Sspecial_display_p);
+   defsubr (&Ssame_window_p);
+   defsubr (&Sdisplay_buffer);
+   defsubr (&Sforce_window_update);
+   defsubr (&Ssplit_window);
+   defsubr (&Senlarge_window);
+   defsubr (&Sshrink_window);
+   defsubr (&Sscroll_up);
+   defsubr (&Sscroll_down);
+   defsubr (&Sscroll_left);
+   defsubr (&Sscroll_right);
+   defsubr (&Sother_window_for_scrolling);
+   defsubr (&Sscroll_other_window);
+   defsubr (&Sminibuffer_selected_window);
+   defsubr (&Srecenter);
+   defsubr (&Swindow_text_height);
+   defsubr (&Smove_to_window_line);
+   defsubr (&Swindow_configuration_p);
+   defsubr (&Swindow_configuration_frame);
+   defsubr (&Sset_window_configuration);
+   defsubr (&Scurrent_window_configuration);
+   defsubr (&Ssave_window_excursion);
+   defsubr (&Sset_window_margins);
+   defsubr (&Swindow_margins);
+   defsubr (&Sset_window_fringes);
+   defsubr (&Swindow_fringes);
+   defsubr (&Sset_window_scroll_bars);
+   defsubr (&Swindow_scroll_bars);
+   defsubr (&Swindow_vscroll);
+   defsubr (&Sset_window_vscroll);
+   defsubr (&Scompare_window_configurations);
+   defsubr (&Swindow_list);
+ }
+ 
+ void
+ keys_of_window ()
+ {
+   initial_define_key (control_x_map, '1', "delete-other-windows");
+   initial_define_key (control_x_map, '2', "split-window");
+   initial_define_key (control_x_map, '0', "delete-window");
+   initial_define_key (control_x_map, 'o', "other-window");
+   initial_define_key (control_x_map, '^', "enlarge-window");
+   initial_define_key (control_x_map, '<', "scroll-left");
+   initial_define_key (control_x_map, '>', "scroll-right");
+ 
+   initial_define_key (global_map, Ctl ('V'), "scroll-up");
+   initial_define_key (meta_map, Ctl ('V'), "scroll-other-window");
+   initial_define_key (meta_map, 'v', "scroll-down");
+ 
+   initial_define_key (global_map, Ctl('L'), "recenter");
+   initial_define_key (meta_map, 'r', "move-to-window-line");
+ }
+ 
+ /* arch-tag: 90a9c576-0590-48f1-a5f1-6c96a0452d9f
+    (do not change this comment) */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]