* isearch.el (isearch-switch-frame-handler): Call
[bpt/emacs.git] / src / window.c
index f11fed9..962bc1f 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985, 1986, 1987, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,12 +29,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "disptab.h"
 #include "keyboard.h"
 
-Lisp_Object Qwindowp;
+Lisp_Object Qwindowp, Qwindow_live_p;
 
 Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
 Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
 
-static void delete_all_subwindows ();
+void delete_all_subwindows ();
 static struct window *decode_window();
 
 /* This is the window in which the terminal's cursor should
@@ -60,9 +60,6 @@ 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;
 
-/* Window that the mouse is over (nil if no mouse support).  */
-Lisp_Object Vmouse_window;
-
 /* Last mouse click data structure (nil if no mouse support).  */
 Lisp_Object Vmouse_event;
 
@@ -105,6 +102,16 @@ DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
   return XTYPE (obj) == Lisp_Window ? Qt : Qnil;
 }
 
+DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0,
+  "Returns t if OBJ is a window which is currently visible.")
+     (obj)
+     Lisp_Object obj;
+{
+  return ((XTYPE (obj) == Lisp_Window
+          && ! NILP (XWINDOW (obj)->buffer))
+         ? Qt : Qnil);
+}
+
 Lisp_Object
 make_window ()
 {
@@ -158,7 +165,7 @@ used by that frame.")
   return FRAME_MINIBUF_WINDOW (XFRAME (frame));
 }
 
-DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 1, 1, 0,
+DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 0, 1, 0,
   "Returns non-nil if WINDOW is a minibuffer window.")
   (window)
      Lisp_Object window;
@@ -190,11 +197,7 @@ POS defaults to point; WINDOW, to the selected window.")
       posint = XINT (pos);
     }
 
-  if (NILP (window))
-    window = selected_window;
-  else
-    CHECK_WINDOW (window, 1);
-  w = XWINDOW (window);
+  w = decode_window (window);
   top = marker_position (w->start);
 
   if (posint < top)
@@ -219,9 +222,7 @@ POS defaults to point; WINDOW, to the selected window.")
 
       /* If that info is not correct, calculate afresh */
       posval = *compute_motion (top, 0, 0, posint, height, 0,
-                               XFASTINT (w->width) - 1
-                               - (XFASTINT (w->width) + XFASTINT (w->left)
-                                  != FRAME_WIDTH (XFRAME (w->frame))),
+                               window_internal_width (w) - 1,
                                XINT (w->hscroll), 0);
 
       return posval.vpos < height ? Qt : Qnil;
@@ -235,7 +236,7 @@ decode_window (window)
   if (NILP (window))
     return XWINDOW (selected_window);
 
-  CHECK_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window, 0);
   return XWINDOW (window);
 }
 
@@ -261,13 +262,9 @@ DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0,
      Lisp_Object window;
 {
   register struct window *w = decode_window (window);
-  register int width = w->width;
+  register int width = XFASTINT (w->width);
 
-  /* If this window does not end at the right margin,
-     must deduct one column for the border */
-  if ((width + w->left) == FRAME_WIDTH (XFRAME (WINDOW_FRAME (w))))
-    return width;
-  return width - 1;
+  return make_number (window_internal_width (w));
 }
 
 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0,
@@ -291,7 +288,7 @@ NCOL should be zero or positive.")
   if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1)))
     args_out_of_range (ncol, Qnil);
   w = decode_window (window);
-  if (w->hscroll != ncol)
+  if (XINT (w->hscroll) != XINT (ncol))
     clip_changed = 1;          /* Prevent redisplay shortcuts */
   w->hscroll = ncol;
   return ncol;
@@ -370,7 +367,7 @@ If they are on the border between WINDOW and its right sibling,\n\
 {
   int x, y;
 
-  CHECK_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window, 0);
   CHECK_CONS (coordinates, 1);
   x = XINT (Fcar (coordinates));
   y = XINT (Fcdr (coordinates));
@@ -427,12 +424,12 @@ window_from_coordinates (frame, x, y, part)
 }
 
 DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
-  "Return window containing row ROW, column COLUMN on FRAME.\n\
+  "Return window containing coordinates X and Y on FRAME.\n\
 If omitted, FRAME defaults to the currently selected frame.\n\
 The top left corner of the frame is considered to be row 0,\n\
 column 0.")
-  (row, column, frame)
-      Lisp_Object row, column, frame;
+  (x, y, frame)
+      Lisp_Object x, y, frame;
 {
   int part;
 
@@ -442,11 +439,11 @@ column 0.")
   else
     CHECK_LIVE_FRAME (frame, 2);
 #endif
-  CHECK_NUMBER (row, 0);
-  CHECK_NUMBER (column, 1);
+  CHECK_NUMBER (x, 0);
+  CHECK_NUMBER (y, 1);
 
   return window_from_coordinates (XFRAME (frame),
-                                 XINT (row), XINT (column),
+                                 XINT (x), XINT (y),
                                  &part);
 }
 
@@ -643,7 +640,7 @@ replace_window (old, replacement)
   /* If OLD is its frame's root_window, then replacement is the new
      root_window for that frame.  */
 
-  if (old == FRAME_ROOT_WINDOW (XFRAME (o->frame)))
+  if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
     FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
 
   p->left = o->left;
@@ -682,12 +679,21 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   register struct window *p;
   register struct window *par;
 
+  /* 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, 0);
-
   p = XWINDOW (window);
+
+  /* It's okay to delete an already-deleted window.  */
+  if (NILP (p->buffer)
+      && NILP (p->hchild)
+      && NILP (p->vchild))
+    return Qnil;
+
   parent = p->parent;
   if (NILP (parent))
     error ("Attempt to delete minibuffer or sole ordinary window");
@@ -695,8 +701,25 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
 
   windows_or_buffers_changed++;
 
-  if (EQ (window, selected_window))
-    Fselect_window (Fnext_window (window, Qnil, Qnil));
+  /* Are we trying to delete any frame's selected window?  */
+  {
+    Lisp_Object frame = WINDOW_FRAME (XWINDOW (window));
+
+    if (EQ (window, FRAME_SELECTED_WINDOW (XFRAME (frame))))
+      {
+       Lisp_Object alternative = Fnext_window (window, Qlambda, Qnil);
+
+       /* If we're about to delete the selected window on the
+          selected frame, then we should use Fselect_window to select
+          the new window.  On the other hand, if we're about to
+          delete the selected window on any other frame, we shouldn't do
+          anything but set the frame's selected_window slot.  */
+       if (EQ (window, selected_window))
+         Fselect_window (alternative);
+       else
+         FRAME_SELECTED_WINDOW (XFRAME (frame)) = alternative;
+      }
+  }
 
   tem = p->buffer;
   /* tem is null for dummy parent windows
@@ -706,7 +729,6 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
       unshow_buffer (p);
       unchain_marker (p->pointm);
       unchain_marker (p->start);
-      p->buffer = Qnil;
     }
 
   tem = p->next;
@@ -731,8 +753,8 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
         set_window_{height,width} will re-position the sibling's
         children.  */
       sib = p->next;
-      XFASTINT (XWINDOW (sib)->top) = p->top;
-      XFASTINT (XWINDOW (sib)->left) = p->left;
+      XWINDOW (sib)->top = p->top;
+      XWINDOW (sib)->left = p->left;
     }
 
   /* Stretch that sibling.  */
@@ -747,12 +769,22 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 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;
+
   return Qnil;
 }
 \f
@@ -776,7 +808,12 @@ minibuffer does not count, only windows from WINDOW's frame count.\n\
 \n\
 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
-above.  If neither nil nor t, restrict to WINDOW's frame.")
+above.  If neither nil nor t, restrict to WINDOW's frame.\n\
+\n\
+If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
+`next-window' to iterate through the entire cycle of acceptable\n\
+windows, eventually ending up back at the window you started with.\n\
+`previous-window' traverses the same cycle, in the reverse order.")
   (window, minibuf, all_frames)
      register Lisp_Object window, minibuf, all_frames;
 {
@@ -786,7 +823,7 @@ above.  If neither nil nor t, restrict to WINDOW's frame.")
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window, 0);
 
   start_window = window;
 
@@ -850,7 +887,7 @@ above.  If neither nil nor t, restrict to WINDOW's frame.")
      we've come all the way around and we're back at the original window.  */
   while (MINI_WINDOW_P (XWINDOW (window))
         && ! EQ (minibuf, Qt)
-        && window != start_window);
+        && ! EQ (window, start_window));
 
   return window;
 }
@@ -873,7 +910,12 @@ count.\n\
 \n\
 Optional third arg ALL-FRAMES t means include windows on all frames.\n\
 ALL-FRAMES nil or omitted means cycle within the frames as specified\n\
-above.  If neither nil nor t, restrict to WINDOW's frame.")
+above.  If neither nil nor t, restrict to WINDOW's frame.\n\
+\n\
+If you use consistent values for MINIBUF and ALL-FRAMES, you can use\n\
+`previous-window' to iterate through the entire cycle of acceptable\n\
+windows, eventually ending up back at the window you started with.\n\
+`next-window' traverses the same cycle, in the reverse order.")
   (window, minibuf, all_frames)
      register Lisp_Object window, minibuf, all_frames;
 {
@@ -883,7 +925,7 @@ above.  If neither nil nor t, restrict to WINDOW's frame.")
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window, 0);
 
   start_window = window;
 
@@ -920,7 +962,16 @@ above.  If neither nil nor t, restrict to WINDOW's frame.")
            tem = WINDOW_FRAME (XWINDOW (window));
 #ifdef MULTI_FRAME
            if (! NILP (all_frames))
-             tem = next_frame (tem, all_frames);
+             /* It's actually important that we use prev_frame here,
+                rather than next_frame.  All the windows acceptable
+                according to the given parameters should form a ring;
+                Fnext_window and Fprevious_window should go back and
+                forth around the ring.  If we use next_frame here,
+                then Fnext_window and Fprevious_window take different
+                paths through the set of acceptable windows.
+                window_loop assumes that these `ring' requirement are
+                met.  */
+             tem = prev_frame (tem, all_frames);
 #endif
            tem = FRAME_ROOT_WINDOW (XFRAME (tem));
 
@@ -948,7 +999,7 @@ above.  If neither nil nor t, restrict to WINDOW's frame.")
      we've come all the way around and we're back at the original window.  */
   while (MINI_WINDOW_P (XWINDOW (window))
         && !EQ (minibuf, Qt)
-        && window != start_window);
+        && !EQ (window, start_window));
 
   return window;
 }
@@ -1113,7 +1164,7 @@ window_loop (type, obj, mini, frames)
                   on the frame, find a new buffer to display there.  */
                if (NILP (XWINDOW (w)->parent))
                  {
-                   Lisp_Object new_buffer = Fother_buffer (obj);
+                   Lisp_Object new_buffer = Fother_buffer (obj, Qnil);
                    if (NILP (new_buffer))
                      new_buffer
                        = Fget_buffer_create (build_string ("*scratch*"));
@@ -1151,7 +1202,7 @@ window_loop (type, obj, mini, frames)
            if (EQ (XWINDOW (w)->buffer, obj))
              {
                /* Find another buffer to show in this window.  */
-               Lisp_Object another_buffer = Fother_buffer (obj);
+               Lisp_Object another_buffer = Fother_buffer (obj, Qnil);
                if (NILP (another_buffer))
                  another_buffer
                    = Fget_buffer_create (build_string ("*scratch*"));
@@ -1170,7 +1221,7 @@ window_loop (type, obj, mini, frames)
 
   return best_window;
 }     
-\f
+
 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
   "Return the window least recently selected or used for display.\n\
 If optional argument FRAMES is t, search all frames.  If FRAME is a\n\
@@ -1227,16 +1278,16 @@ Only the frame WINDOW is on is affected.")
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window, 0);
 
   w = XWINDOW (window);
   top = XFASTINT (w->top);
 
-  window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME(w));
+  window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_FRAME (w));
 
   Fset_buffer (w->buffer);
   SET_PT (marker_position (w->start));
-  Frecenter (make_number (top));
+  Frecenter (make_number (top - FRAME_MENU_BAR_LINES (XFRAME (WINDOW_FRAME (w)))));
 
   set_buffer_internal (obuf);
   SET_PT (opoint);
@@ -1296,10 +1347,10 @@ check_min_window_sizes ()
 
 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
    minimum allowable size.  */
-extern void
+void
 check_frame_size (frame, rows, cols)
-FRAME_PTR frame;
-int *rows, *cols;
+     FRAME_PTR frame;
+     int *rows, *cols;
 {
   /* For height, we have to see whether the frame has a minibuffer, and
      whether it wants a mode line.  */
@@ -1497,7 +1548,7 @@ before each command.")
   register struct window *w;
   register struct window *ow = XWINDOW (selected_window);
 
-  CHECK_WINDOW (window, 0);
+  CHECK_LIVE_WINDOW (window, 0);
 
   w = XWINDOW (window);
 
@@ -1550,7 +1601,7 @@ DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
 BUFFER can be a buffer or a buffer name.\n\
 If BUFFER is shown already in some window, just use that one,\n\
 unless the window is the selected window and the optional second\n\
-argument NOT_THIS_WINDOW is non-nil.\n\
+argument NOT-THIS-WINDOW is non-nil (interactively, with prefix arg).\n\
 Returns the window displaying BUFFER.")
   (buffer, not_this_window)
      register Lisp_Object buffer, not_this_window;
@@ -1607,9 +1658,8 @@ Returns the window displaying BUFFER.")
 
       if (!NILP (window)
          && window_height (window) >= split_height_threshold
-         &&
-         (XFASTINT (XWINDOW (window)->width)
-          == FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (window))))))
+         && (XFASTINT (XWINDOW (window)->width)
+             == FRAME_WIDTH (XFRAME (WINDOW_FRAME (XWINDOW (window))))))
        window = Fsplit_window (window, Qnil, Qnil);
       else
        {
@@ -1706,7 +1756,7 @@ and put SIZE columns in the first of the pair.")
   if (NILP (window))
     window = selected_window;
   else
-    CHECK_WINDOW (window, 0);
+    CHECK_LIVE_WINDOW (window, 0);
 
   o = XWINDOW (window);
 
@@ -1986,6 +2036,36 @@ window_internal_height (w)
   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_internal_width (w)
+     struct window *w;
+{
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+  int left = XINT (w->left);
+  int width = XINT (w->width);
+
+  /* If this window is flush against the right edge of the frame, its
+     internal width is its full width.  */
+  if (left + width >= FRAME_WIDTH (f))
+    return width;
+
+  /* If we are not flush right, then our rightmost columns are
+     occupied by some sort of separator.  */
+
+  /* Scroll bars occupy a few columns.  */
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+    return width - VERTICAL_SCROLL_BAR_WIDTH;
+
+  /* The column of `|' characters separating side-by-side windows
+     occupies one column only.  */
+  return width - 1;
+}
+
+
 /* Scroll contents of window WINDOW up N lines.  */
 
 void
@@ -2113,7 +2193,7 @@ When calling from a program, supply a number as argument or nil.")
 }
 
 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
-  "Scroll text of next window upward ARG lines; or near full screen if no ARG.\n\
+  "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
 The next window is the one below the current one; or the one at the top\n\
 if the current one is at the bottom.\n\
 When calling from a program, supply a number as argument or nil.\n\
@@ -2141,9 +2221,21 @@ showing that buffer, popping the buffer up if necessary.")
        window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
     }
   else
-    /* Nothing specified; pick a neighboring window.  */
-    window = Fnext_window (selected_window, Qnil, Qt);
-  CHECK_WINDOW (window, 0);
+    {
+      /* 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, 0);
 
   if (EQ (window, selected_window))
     error ("There is no other window");
@@ -2170,7 +2262,7 @@ showing that buffer, popping the buffer up if necessary.")
     }
 
   Fset_marker (w->pointm, make_number (point), Qnil);
-  unbind_to (count);
+  unbind_to (count, Qnil);
 
   return Qnil;
 }
@@ -2183,7 +2275,7 @@ Default for ARG is window width minus 2.")
 {
 
   if (NILP (arg))
-    XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
+    XFASTINT (arg) = window_internal_width (XWINDOW (selected_window)) - 2;
   else
     arg = Fprefix_numeric_value (arg);
 
@@ -2200,7 +2292,7 @@ Default for ARG is window width minus 2.")
      register Lisp_Object arg;
 {
   if (NILP (arg))
-    XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2;
+    XFASTINT (arg) = window_internal_width (XWINDOW (selected_window)) - 2;
   else
     arg = Fprefix_numeric_value (arg);
 
@@ -2296,14 +2388,23 @@ struct save_window_data
     int size_from_Lisp_Vector_struct;
     struct Lisp_Vector *next_from_Lisp_Vector_struct;
     Lisp_Object frame_width, frame_height;
+    Lisp_Object selected_frame;
     Lisp_Object current_window;
     Lisp_Object current_buffer;
     Lisp_Object minibuf_scroll_window;
     Lisp_Object root_window;
+    Lisp_Object focus_frame;
     /* A vector, interpreted as a struct saved_window */
     Lisp_Object saved_windows;
   };
-#define SAVE_WINDOW_DATA_SIZE 7 /* Arg to Fmake_vector */
+
+/* Arg to Fmake_vector */
+#define SAVE_WINDOW_DATA_SIZE                                          \
+  ((sizeof (struct save_window_data)                                   \
+    - (sizeof (struct Lisp_Vector)                                     \
+       /* Don't count the contents member of the struct Lisp_Vector */ \
+       - sizeof (Lisp_Object)))                                                \
+   / sizeof (Lisp_Object))
 
 /* This is saved as a Lisp_Vector */
 struct saved_window
@@ -2344,20 +2445,12 @@ by `current-window-configuration' (which see).")
      (configuration)
      Lisp_Object configuration;
 {
-  register struct window *w;
   register struct save_window_data *data;
   struct Lisp_Vector *saved_windows;
-  register struct saved_window *p;
-  register Lisp_Object tem;
   Lisp_Object new_current_buffer;
-  int k;
+  Lisp_Object frame;
   FRAME_PTR f;
 
-  /* Save screen height here so we can go back to it at the end.  */
-  int previous_frame_height;
-  int previous_frame_width;
-  int frame_size_change;
-
   while (XTYPE (configuration) != Lisp_Window_Configuration)
     {
       configuration = wrong_type_argument (intern ("window-configuration-p"),
@@ -2367,144 +2460,184 @@ by `current-window-configuration' (which see).")
   data = (struct save_window_data *) XVECTOR (configuration);
   saved_windows = XVECTOR (data->saved_windows);
 
-  f = XFRAME (XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame);
-
-  if (XFASTINT (data->frame_height) != FRAME_HEIGHT (f)
-      || XFASTINT (data->frame_width) != FRAME_WIDTH (f))
-    {
-      previous_frame_height = FRAME_HEIGHT (f);
-      previous_frame_width =  FRAME_WIDTH  (f);
-      frame_size_change = 1;
-
-      change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
-    }
-  else
-    frame_size_change = 0;
-
-  windows_or_buffers_changed++;
   new_current_buffer = data->current_buffer;
   if (NILP (XBUFFER (new_current_buffer)->name))
     new_current_buffer = Qnil;
 
-  /* 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 the buffer saved in the configuration is now
-     dead.  */
-  delete_all_subwindows (XWINDOW (FRAME_ROOT_WINDOW (f)));
+  frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
+  f = XFRAME (frame);
 
-  for (k = 0; k < saved_windows->size; k++)
+  /* 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))
     {
-      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
+      register struct window *w;
+      register struct saved_window *p;
+      int k;
+
+      /* 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_height = FRAME_HEIGHT (f);
+      int previous_frame_width =  FRAME_WIDTH  (f);
+
+      if (XFASTINT (data->frame_height) != previous_frame_height
+         || XFASTINT (data->frame_width) != previous_frame_width)
+       change_frame_size (f, data->frame_height, data->frame_width, 0, 0);
+
+      windows_or_buffers_changed++;
+
+      /* 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++)
        {
-         w->prev = Qnil;
-         if (!NILP (w->parent))
-           {
-             if (EQ (p->width, XWINDOW (w->parent)->width))
-               {
-                 XWINDOW (w->parent)->vchild = p->window;
-                 XWINDOW (w->parent)->hchild = Qnil;
-               }
-             else
-               {
-                 XWINDOW (w->parent)->hchild = p->window;
-                 XWINDOW (w->parent)->vchild = Qnil;
-               }
-           }
-       }
+         p = SAVED_WINDOW_N (saved_windows, k);
+         w = XWINDOW (p->window);
+         w->next = Qnil;
 
-      /* If we squirreled away the buffer in the window's height,
-        restore it now.  */
-      if (XTYPE (w->height) == Lisp_Buffer)
-       w->buffer = w->height;
-      w->left = p->left;
-      w->top = p->top;
-      w->width = p->width;
-      w->height = p->height;
-      w->hscroll = p->hscroll;
-      w->display_table = p->display_table;
-      XFASTINT (w->last_modified) = 0;
+         if (!NILP (p->parent))
+           w->parent = SAVED_WINDOW_N (saved_windows,
+                                       XFASTINT (p->parent))->window;
+         else
+           w->parent = Qnil;
 
-      /* 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.  */
+         if (!NILP (p->prev))
            {
-             w->buffer = p->buffer;
-             w->start_at_line_beg = p->start_at_line_beg;
-             set_marker_restricted (w->start, Fmarker_position (p->start), w->buffer);
-             set_marker_restricted (w->pointm, Fmarker_position (p->pointm), w->buffer);
-             Fset_marker (XBUFFER (w->buffer)->mark,
-                          Fmarker_position (p->mark), w->buffer);
-
-             if (!EQ (p->buffer, new_current_buffer) &&
-                 XBUFFER (p->buffer) == current_buffer)
-               Fgoto_char (w->pointm);
+             w->prev = SAVED_WINDOW_N (saved_windows,
+                                       XFASTINT (p->prev))->window;
+             XWINDOW (w->prev)->next = p->window;
            }
-         else if (NILP (XBUFFER (w->buffer)->name))
-           /* Else if window's old buffer is dead too, get a live one.  */
+         else
            {
-             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;
+             w->prev = Qnil;
+             if (!NILP (w->parent))
+               {
+                 if (EQ (p->width, XWINDOW (w->parent)->width))
+                   {
+                     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 (XTYPE (w->height) == Lisp_Buffer)
+           w->buffer = w->height;
+         w->left = p->left;
+         w->top = p->top;
+         w->width = p->width;
+         w->height = p->height;
+         w->hscroll = p->hscroll;
+         w->display_table = p->display_table;
+         XFASTINT (w->last_modified) = 0;
+
+         /* Reinstall the saved buffer and pointers into it.  */
+         if (NILP (p->buffer))
+           w->buffer = p->buffer;
          else
-           /* Keeping window's old buffer; make sure the markers are real.  */
-           /* Else if window's old buffer is dead too, get a live one.  */
            {
-             /* 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 (w->pointm,
-                                      make_number (BUF_PT (XBUFFER (w->buffer))),
-                                      w->buffer);
-             w->start_at_line_beg = Qt;
+             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,
+                                        Fmarker_position (p->start),
+                                        w->buffer);
+                 set_marker_restricted (w->pointm,
+                                        Fmarker_position (p->pointm),
+                                        w->buffer);
+                 Fset_marker (XBUFFER (w->buffer)->mark,
+                              Fmarker_position (p->mark), w->buffer);
+
+                 /* As documented in Fcurrent_window_configuration, don't
+                    save the location of point in the buffer which was current
+                    when the window configuration was recorded.  */
+                 if (!EQ (p->buffer, new_current_buffer) &&
+                     XBUFFER (p->buffer) == current_buffer)
+                   Fgoto_char (w->pointm);
+               }
+             else if (NILP (XBUFFER (w->buffer)->name))
+               /* Else if window's old buffer is dead too, get a live 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.  Else if window's old buffer is dead too,
+                  get a live one.  */
+               {
+                 /* 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 (w->pointm,
+                                          (make_number
+                                           (BUF_PT (XBUFFER (w->buffer)))),
+                                          w->buffer);
+                 w->start_at_line_beg = Qt;
+               }
            }
        }
-    }
 
-  FRAME_ROOT_WINDOW (f) = data->root_window;
+      FRAME_ROOT_WINDOW (f) = data->root_window;
+      Fselect_window (data->current_window);
 
 #ifdef MULTI_FRAME
-  if (f != selected_frame && ! FRAME_TERMCAP_P (f))
-    Fselect_frame (WINDOW_FRAME (XWINDOW (data->root_window)), Qnil);
+      if (NILP (data->focus_frame)
+         || (XTYPE (data->focus_frame) == Lisp_Frame
+             && FRAME_LIVE_P (XFRAME (data->focus_frame))))
+       Fredirect_frame_focus (frame, data->focus_frame);
 #endif
 
-  /* Set the screen height to the value it had before this function.  */
-  if (frame_size_change)
-    change_frame_size (f, previous_frame_height, previous_frame_width, 0, 0);
+#if 0 /* I don't understand why this is needed, and it causes problems
+         when the frame's old selected window has been deleted.  */
+#ifdef MULTI_FRAME
+      if (f != selected_frame && ! FRAME_TERMCAP_P (f))
+       Fselect_frame (WINDOW_FRAME (XWINDOW (data->root_window)), Qnil);
+#endif
+#endif
 
-  if (f == selected_frame)
-    {
-      Fselect_window (data->current_window);
-      if (!NILP (new_current_buffer))
-       Fset_buffer (new_current_buffer);
-      else
-       Fset_buffer (XWINDOW (selected_window)->buffer);
+      /* Set the screen height to the value it had before this function.  */
+      if (previous_frame_height != FRAME_HEIGHT (f)
+         || previous_frame_width != FRAME_WIDTH (f))
+       change_frame_size (f, previous_frame_height, previous_frame_width,
+                          0, 0);
     }
 
+#ifdef MULTI_FRAME
+  /* Fselect_window will have made f the selected frame, so we
+     reselect the proper frame here.  Fselect_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)))
+    Fselect_frame (data->selected_frame, Qnil);
+#endif
+
+  if (!NILP (new_current_buffer))
+    Fset_buffer (new_current_buffer);
+
   Vminibuf_scroll_window = data->minibuf_scroll_window;
   return (Qnil);
 }
@@ -2512,18 +2645,26 @@ by `current-window-configuration' (which see).")
 /* Mark all windows now on frame as deleted
    by setting their buffers to nil.  */
 
-static void
+void
 delete_all_subwindows (w)
      register struct window *w;
 {
-  w->height = w->buffer;       /* See Fset_window_configuration for excuse.  */
-  w->buffer = Qnil;
   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->height = w->buffer;       /* See Fset_window_configuration for excuse.  */
+
+  /* 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;
 }
 \f
 static int
@@ -2618,7 +2759,9 @@ If FRAME is nil or omitted, use the selected frame.\n\
 This describes the number of windows, their sizes and current buffers,\n\
 and for each displayed buffer, where display starts, and the positions of\n\
 point and mark.  An exception is made for point in the current buffer:\n\
-its value is -not- saved.")
+its value is -not- saved.\n\
+This also records the currently selected frame, and FRAME's focus\n\
+redirection (see `redirect-frame-focus').")
   (frame)
      Lisp_Object frame;
 {
@@ -2642,10 +2785,14 @@ its value is -not- saved.")
                                  Qnil));
   XFASTINT (data->frame_width) = FRAME_WIDTH (f);
   XFASTINT (data->frame_height) = FRAME_HEIGHT (f);
+#ifdef MULTI_FRAME
+  XSET (data->selected_frame, Lisp_Frame, selected_frame);
+#endif
   data->current_window = FRAME_SELECTED_WINDOW (f);
   XSET (data->current_buffer, Lisp_Buffer, current_buffer);
   data->minibuf_scroll_window = Vminibuf_scroll_window;
   data->root_window = FRAME_ROOT_WINDOW (f);
+  data->focus_frame = FRAME_FOCUS_FRAME (f);
   tem = Fmake_vector (make_number (n_windows), Qnil);
   data->saved_windows = tem;
   for (i = 0; i < n_windows; i++)
@@ -2726,6 +2873,9 @@ syms_of_window ()
   Qwindowp = intern ("windowp");
   staticpro (&Qwindowp);
 
+  Qwindow_live_p = intern ("window-live-p");
+  staticpro (&Qwindow_live_p);
+
 #ifndef MULTI_FRAME
   /* Make sure all windows get marked */
   staticpro (&minibuf_window);
@@ -2744,22 +2894,18 @@ Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\
 work using this function.");
   Vdisplay_buffer_function = Qnil;
 
-  DEFVAR_LISP ("mouse-window", &Vmouse_window,
-     "Window that the last mouse click occurred on.");
-  Vmouse_window = Qnil;
-
   DEFVAR_LISP ("mouse-event", &Vmouse_event,
      "The last mouse-event object.  A list of four elements:\n\
   ((X-POS Y-POS) WINDOW FRAME-PART KEYSEQ).\n\
 KEYSEQ is a string, the key sequence to be looked up in the mouse maps.\n\
 WINDOW is the window that the click applies do.\n\
-If FRAME-PART is non-nil, the event was on a scrollbar;\n\
-then Y-POS is really the total length of the scrollbar, while X-POS is\n\
-the relative position of the scrollbar's value within that total length.\n\
+If FRAME-PART is non-nil, the event was on a scroll bar;\n\
+then Y-POS is really the total length of the scroll bar, while X-POS is\n\
+the relative position of the scroll bar's value within that total length.\n\
 FRAME-PART is one of the following symbols:\n\
- `vertical-scrollbar', `vertical-slider',\n\
+ `vertical-scroll-bar', `vertical-slider',\n\
  `vertical-thumbup', `vertical-thumbdown',\n\
- `horizontal-scrollbar', `horizontal-slider',\n\
+ `horizontal-scroll-bar', `horizontal-slider',\n\
  `horizontal-thumbleft', `horizontal-thumbright'");
   Vmouse_event = Qnil;
 
@@ -2810,6 +2956,7 @@ If there is only one window, it is split regardless of this value.");
   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);