* window.c (run_window_configuration_change_hook): New function.
[bpt/emacs.git] / src / window.c
index 94e56d1..5b0d8f4 100644 (file)
@@ -1,13 +1,14 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
    Copyright (C) 1985, 1986, 1987, 1993, 1994, 1995, 1996, 1997, 1998, 2000,
-                 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+                 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)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -36,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #include "dispextern.h"
 #include "blockinput.h"
 #include "intervals.h"
+#include "termhooks.h"         /* For FRAME_TERMINAL.  */
 
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
@@ -64,6 +66,7 @@ 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_2 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, int, int));
 static int freeze_window_start P_ ((struct window *, void *));
@@ -191,6 +194,10 @@ Lisp_Object Qtemp_buffer_show_hook;
 
 EMACS_INT split_height_threshold;
 
+/* How to split windows (horizontally/vertically/hybrid).  */
+
+Lisp_Object Vsplit_window_preferred_function;
+
 /* Number of lines of continuity in scrolling by screenfuls.  */
 
 EMACS_INT next_screen_context_lines;
@@ -558,6 +565,15 @@ use  (let ((edges (window-edges))) (- (nth 2 edges) (nth 0 edges))).  */)
   return make_number (window_box_text_cols (decode_any_window (window)));
 }
 
+DEFUN ("window-full-width-p", Fwindow_full_width_p, Swindow_full_width_p, 0, 1, 0,
+       doc: /* Return t if WINDOW is as wide as its frame.
+WINDOW defaults to the selected window.  */)
+     (window)
+     Lisp_Object window;
+{
+  return WINDOW_FULL_WIDTH_P (decode_any_window (window)) ? Qt : Qnil;
+}
+
 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 defaults to the selected window.  */)
@@ -784,7 +800,7 @@ coordinates_in_window (w, x, y)
       if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
          || WINDOW_RIGHTMOST_P (w))
        {
-         if (!WINDOW_LEFTMOST_P (w) && abs (*x - x0) < grabbable_width)
+         if (!WINDOW_LEFTMOST_P (w) && eabs (*x - x0) < grabbable_width)
            {
              /* Convert X and Y to window relative coordinates.
                 Vertical border is at the left edge of window.  */
@@ -795,7 +811,7 @@ coordinates_in_window (w, x, y)
        }
       else
        {
-         if (abs (*x - x1) < grabbable_width)
+         if (eabs (*x - x1) < grabbable_width)
            {
              /* Convert X and Y to window relative coordinates.
                 Vertical border is at the right edge of window.  */
@@ -843,7 +859,7 @@ coordinates_in_window (w, x, y)
       if (!w->pseudo_window_p
          && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)
          && !WINDOW_RIGHTMOST_P (w)
-         && (abs (*x - right_x) < grabbable_width))
+         && (eabs (*x - right_x) < grabbable_width))
        {
          /* Convert X and Y to window relative coordinates.
             Vertical border is at the right edge of window.  */
@@ -1534,7 +1550,7 @@ delete_window (window)
        if (!EQ (window, pwindow))
          break;
        /* Otherwise, try another window for SWINDOW.  */
-       swindow = Fnext_window (swindow, Qlambda, Qnil);;
+       swindow = Fnext_window (swindow, Qlambda, Qnil);
 
        /* If we get back to the frame's selected window,
           it means there was no acceptable alternative,
@@ -1780,12 +1796,28 @@ candidate_window_p (window, owindow, minibuf, all_frames)
   else if (EQ (all_frames, Qvisible))
     {
       FRAME_SAMPLE_VISIBILITY (f);
-      candidate_p = FRAME_VISIBLE_P (f);
+      candidate_p = FRAME_VISIBLE_P (f)
+       && (FRAME_TERMINAL (XFRAME (w->frame))
+           == FRAME_TERMINAL (XFRAME (selected_frame)));
+
     }
   else if (INTEGERP (all_frames) && XINT (all_frames) == 0)
     {
       FRAME_SAMPLE_VISIBILITY (f);
-      candidate_p = FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f);
+      candidate_p = (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)
+#ifdef HAVE_X_WINDOWS
+                    /* Yuck!!  If we've just created the frame and the
+                       window-manager requested the user to place it
+                       manually, the window may still not be considered
+                       `visible'.  I'd argue it should be at least
+                       something like `iconified', but don't know how to do
+                       that yet.  --Stef  */
+                    || (FRAME_X_P (f) && f->output_data.x->asked_for_visible
+                        && !f->output_data.x->has_been_visible)
+#endif
+                    )
+       && (FRAME_TERMINAL (XFRAME (w->frame))
+           == FRAME_TERMINAL (XFRAME (selected_frame)));
     }
   else if (WINDOWP (all_frames))
     candidate_p = (EQ (FRAME_MINIBUF_WINDOW (f), all_frames)
@@ -2154,8 +2186,10 @@ window_loop (type, obj, mini, frames)
                if (NILP (best_window))
                  best_window = window;
                else if (EQ (window, selected_window))
-                 /* For compatibility with 20.x, prefer to return
-                    selected-window.  */
+                 /* Prefer to return selected-window.  */
+                 RETURN_UNGCPRO (window);
+               else if (EQ (Fwindow_frame (window), selected_frame))
+                 /* Prefer windows on the current frame.  */
                  best_window = window;
              }
            break;
@@ -2316,6 +2350,8 @@ check_all_windows ()
 
 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
        doc: /* Return the window least recently selected or used for display.
+\(LRU means Least Recently Used.)
+
 Return a full-width window if possible.
 A minibuffer window is never a candidate.
 A dedicated window is never a candidate, unless DEDICATED is non-nil,
@@ -2553,7 +2589,6 @@ check_frame_size (frame, rows, cols)
     *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
@@ -2636,12 +2671,12 @@ window_fixed_size_p (w, width_p, check_siblings_p)
        {
          Lisp_Object child;
 
-         for (child = w->prev; !NILP (child); child = XWINDOW (child)->prev)
+         for (child = w->prev; WINDOWP (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)
+           for (child = w->next; WINDOWP (child); child = XWINDOW (child)->next)
              if (!window_fixed_size_p (XWINDOW (child), width_p, 0))
                break;
 
@@ -2655,6 +2690,35 @@ window_fixed_size_p (w, width_p, check_siblings_p)
   return fixed_p;
 }
 
+/* Return the minimum size for leaf window W.  WIDTH_P non-zero means
+   take into account fringes and the scrollbar of W.  WIDTH_P zero means
+   take into account mode-line of W.  Return 1 for the minibuffer.  */
+
+static int
+window_min_size_2 (w, width_p)
+     struct window *w;
+     int width_p;
+{
+  int size;
+  
+  if (width_p)
+    size = max (window_min_width,
+               (MIN_SAFE_WINDOW_WIDTH
+                + WINDOW_FRINGE_COLS (w)
+                + WINDOW_SCROLL_BAR_COLS (w)));
+  else if (MINI_WINDOW_P (w))
+    size = 1;
+  else
+    size = max (window_min_height,
+               (MIN_SAFE_WINDOW_HEIGHT
+                /* Don't count the header-line here.  It would break
+                   splitting a window with a header-line when the new
+                   window shall have a height of two (calculator does
+                   that). */
+                + (WINDOW_WANTS_MODELINE_P (w) ? 1 : 0)));
+
+  return size;
+}
 
 /* Return the minimum size of window W, not taking fixed-width windows
    into account.  WIDTH_P non-zero means return the minimum width,
@@ -2724,22 +2788,7 @@ window_min_size_1 (w, width_p)
        }
     }
   else
-    {
-      if (width_p)
-       size = max (window_min_width,
-                   (MIN_SAFE_WINDOW_WIDTH
-                    + WINDOW_FRINGE_COLS (w)
-                    + WINDOW_SCROLL_BAR_COLS (w)));
-      else
-       {
-         if (MINI_WINDOW_P (w)
-             || (!WINDOW_WANTS_MODELINE_P (w)
-                 && !WINDOW_WANTS_HEADER_LINE_P (w)))
-           size = 1;
-         else
-           size = window_min_height;
-       }
-    }
+    size = window_min_size_2 (w, width_p);
 
   return size;
 }
@@ -2981,11 +3030,6 @@ size_window (window, size, width_p, nodelete_p, first_only, last_only)
   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);
 
@@ -2996,22 +3040,23 @@ size_window (window, size, width_p, nodelete_p, first_only, last_only)
     {
       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));
+      safe_min_size = window_min_size_2 (w, 1);
     }
   else
     {
       old_size = XINT (w->total_lines);
       min_size = window_min_height;
-      safe_min_size = MIN_SAFE_WINDOW_HEIGHT;
+      safe_min_size = window_min_size_2 (w, 0);
     }
 
   if (old_size < min_size && nodelete_p != 2)
     w->too_small_ok = Qt;
 
+  /* Move the following test here since otherwise the
+     preceding test doesn't make sense.  martin. */
+  if (nodelete_p == 2)
+    nodelete_p = 0;
+
   /* Maybe delete WINDOW if it's too small.  */
   if (nodelete_p != 1 && !NILP (w->parent))
     {
@@ -3262,6 +3307,25 @@ Fset_window_buffer_unwind (obuf)
 EXFUN (Fset_window_fringes, 4);
 EXFUN (Fset_window_scroll_bars, 4);
 
+void
+run_window_configuration_change_hook (struct frame *f)
+{
+  if (! NILP (Vwindow_configuration_change_hook)
+      && ! NILP (Vrun_hooks))
+    {
+      int count = SPECPDL_INDEX ();
+      if (SELECTED_FRAME () != f)
+       {
+         Lisp_Object frame;
+         XSETFRAME (frame, f);
+         record_unwind_protect (Fselect_frame, Fselected_frame ());
+         Fselect_frame (frame);
+       }
+      call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+      unbind_to (count, Qnil);
+    }
+}
+
 /* 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
@@ -3276,6 +3340,7 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
   struct window *w = XWINDOW (window);
   struct buffer *b = XBUFFER (buffer);
   int count = SPECPDL_INDEX ();
+  int samebuf = EQ (buffer, w->buffer);
 
   w->buffer = buffer;
 
@@ -3294,16 +3359,28 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_p)
   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);
+  if (!(keep_margins_p && samebuf))
+    { /* If we're not actually changing the buffer, Don't reset hscroll and
+        vscroll.  This case happens for example when called from
+        change_frame_size_1, where we use a dummy call to
+        Fset_window_buffer on the frame's selected window (and no other)
+        just in order to run window-configuration-change-hook.
+        Resetting hscroll and vscroll here is problematic for things like
+        image-mode and doc-view-mode since it resets the image's position
+        whenever we resize the frame.  */
+      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);
+    }
+  /* Maybe we could move this into the `if' but it's not obviously safe and
+     I doubt it's worth the trouble.  */
   windows_or_buffers_changed++;
 
   /* We must select BUFFER for running the window-scroll-functions.
@@ -3350,10 +3427,7 @@ set_window_buffer (window, buffer, run_hooks_p, keep_margins_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);
+      run_window_configuration_change_hook (XFRAME (WINDOW_FRAME (w)));
     }
 
   unbind_to (count, Qnil);
@@ -3428,6 +3502,22 @@ selects the buffer of the selected window before each command.  */)
   if (EQ (window, selected_window))
     return 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));
+      /* Fselect_frame called us back so we've done all the work already.  */
+      eassert (EQ (window, selected_window));
+      return window;
+    }
+  else
+    sf->selected_window = window;
+
   /* Store the current buffer's actual point into the
      old selected window.  It belongs to that window,
      and when the window is not selected, must be in the window.  */
@@ -3441,18 +3531,6 @@ selects the buffer of the selected window before each command.  */)
     }
 
   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));
-    }
-  else
-    sf->selected_window = window;
 
   if (NILP (norecord))
     record_buffer (w->buffer);
@@ -3632,7 +3710,7 @@ 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;
+     Lisp_Object buffer, not_this_window, frame;
 {
   register Lisp_Object window, tem, swp;
   struct frame *f;
@@ -3704,13 +3782,12 @@ displayed.  */)
       || !NILP (XWINDOW (FRAME_ROOT_WINDOW (f))->dedicated))
     {
       Lisp_Object frames;
+      struct gcpro gcpro1;
+      GCPRO1 (buffer);
 
       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.
@@ -3733,26 +3810,31 @@ displayed.  */)
       else
        window = Fget_largest_window (frames, Qt);
 
-      /* If we got a tall enough full-width window that can be split,
-        split it.  */
+      /* If the largest window is tall enough, full-width, and either eligible
+        for splitting or the only window, 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);
+         && WINDOW_FULL_WIDTH_P (XWINDOW (window))
+              && (window_height (window) >= split_height_threshold
+                  || (NILP (XWINDOW (window)->parent)))
+         && (window_height (window)
+             >= (2 * window_min_size_2 (XWINDOW (window), 0))))
+       window = call1 (Vsplit_window_preferred_function, window);
       else
        {
          Lisp_Object upper, lower, other;
 
          window = Fget_lru_window (frames, Qt);
-         /* If the LRU window is selected, and big enough,
-            and can be split, split it.  */
+         /* If the LRU window is tall enough, and either eligible for
+            splitting and selected or the only window, 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);
+                  && ((EQ (window, selected_window)
+                       && window_height (window) >= split_height_threshold)
+                      || (NILP (XWINDOW (window)->parent)))
+                  && (window_height (window)
+                      >= (2 * window_min_size_2 (XWINDOW (window), 0))))
+           window = call1 (Vsplit_window_preferred_function, window);
          else
            window = Fget_lru_window (frames, Qnil);
          /* If Fget_lru_window returned nil, try other approaches.  */
@@ -3798,6 +3880,7 @@ displayed.  */)
                              0);
            }
        }
+      UNGCPRO;
     }
   else
     window = Fget_lru_window (Qnil, Qnil);
@@ -4000,9 +4083,11 @@ See Info node `(elisp)Splitting Windows' for more details and examples.*/)
 
   if (NILP (horflag))
     {
-      if (size_int < window_min_height)
+      int window_safe_height = window_min_size_2 (o, 0);
+      
+      if (size_int < window_safe_height)
        error ("Window height %d too small (after splitting)", size_int);
-      if (size_int + window_min_height > XFASTINT (o->total_lines))
+      if (size_int + window_safe_height > XFASTINT (o->total_lines))
        error ("Window height %d too small (after splitting)",
               XFASTINT (o->total_lines) - size_int);
       if (NILP (o->parent)
@@ -4015,10 +4100,11 @@ See Info node `(elisp)Splitting Windows' for more details and examples.*/)
     }
   else
     {
-      if (size_int < window_min_width)
+      int window_safe_width = window_min_size_2 (o, 1);
+      
+      if (size_int < window_safe_width)
        error ("Window width %d too small (after splitting)", size_int);
-
-      if (size_int + window_min_width > XFASTINT (o->total_cols))
+      if (size_int + window_safe_width > XFASTINT (o->total_cols))
        error ("Window width %d too small (after splitting)",
               XFASTINT (o->total_cols) - size_int);
       if (NILP (o->parent)
@@ -4110,8 +4196,8 @@ too small.  */)
 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "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.  Only
-siblings to the right or below are changed.  */)
+Interactively, if an argument is not given, make the window one line smaller.
+Only siblings to the right or below are changed.  */)
      (arg, side)
      Lisp_Object arg, side;
 {
@@ -4237,10 +4323,10 @@ enlarge_window (window, delta, horiz_flag)
 
   /* Find the total we can get from other siblings without deleting them.  */
   maximum = 0;
-  for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
+  for (next = p->next; WINDOWP (next); next = XWINDOW (next)->next)
     maximum += (*sizefun) (next) - window_min_size (XWINDOW (next),
                                                    horiz_flag, 0, 0);
-  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+  for (prev = p->prev; WINDOWP (prev); prev = XWINDOW (prev)->prev)
     maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
                                                    horiz_flag, 0, 0);
 
@@ -4388,10 +4474,10 @@ enlarge_window (window, delta, horiz_flag)
          Lisp_Object s;
          int n = 1;
 
-         for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
+         for (s = w->next; WINDOWP (s); s = XWINDOW (s)->next)
            if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
-         for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
+         for (s = w->prev; WINDOWP (s); s = XWINDOW (s)->prev)
            if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
 
@@ -4499,7 +4585,7 @@ adjust_window_trailing_edge (window, delta, horiz_flag)
 
       /* Don't make this window too small.  */
       if (XINT (CURSIZE (window)) + delta
-         < (horiz_flag ? window_min_width : window_min_height))
+         < window_min_size_2 (XWINDOW (window), horiz_flag))
        {
          Fset_window_configuration (old_config);
          error ("Cannot adjust window size as specified");
@@ -4647,7 +4733,7 @@ shrink_window_lowest_first (w, height)
       /* 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)
+      for (child = w->vchild; WINDOWP (child); child = XWINDOW (child)->next)
        last_child = child;
 
       /* Assign new heights.  We leave only MIN_SAFE_WINDOW_HEIGHT.  */
@@ -5443,7 +5529,7 @@ scroll_command (n, direction)
 {
   int count = SPECPDL_INDEX ();
 
-  xassert (abs (direction) == 1);
+  xassert (eabs (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.  */
@@ -5995,10 +6081,8 @@ zero means top of window, negative means relative to bottom of window.  */)
 
 struct save_window_data
   {
-    EMACS_INT size_from_Lisp_Vector_struct;
+    EMACS_UINT size;
     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;
@@ -6006,19 +6090,25 @@ struct save_window_data
     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;
+
+    /* All fields above are traced by the GC.
+       From `fame-cols' down, the fields are ignored by the GC.  */
+
+    int frame_cols, frame_lines, frame_menu_bar_lines;
+    int frame_tool_bar_lines;
+    /* Record the values of window-min-width and window-min-height
+       so that window sizes remain consistent with them.  */
+    int min_width, min_height;
   };
 
 /* 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;
+  EMACS_UINT size;
   struct Lisp_Vector *next_from_Lisp_Vector_struct;
 
   Lisp_Object window;
@@ -6151,18 +6241,20 @@ the return value is nil.  Otherwise the value is t.  */)
         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 (data->frame_lines != previous_frame_lines
+         || data->frame_cols != previous_frame_cols)
+       change_frame_size (f, data->frame_lines,
+                          data->frame_cols, 0, 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
-      if (XFASTINT (data->frame_menu_bar_lines)
+      if (data->frame_menu_bar_lines
          != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
+       x_set_menu_bar_lines (f, make_number (data->frame_menu_bar_lines),
+                             make_number (0));
 #ifdef HAVE_WINDOW_SYSTEM
-      if (XFASTINT (data->frame_tool_bar_lines)
+      if (data->frame_tool_bar_lines
          != previous_frame_tool_bar_lines)
-       x_set_tool_bar_lines (f, data->frame_tool_bar_lines, make_number (0));
+       x_set_tool_bar_lines (f, make_number (data->frame_tool_bar_lines),
+                             make_number (0));
 #endif
 #endif
 
@@ -6396,8 +6488,8 @@ the return value is nil.  Otherwise the value is t.  */)
     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);
+  window_min_height = data->min_height;
+  window_min_width = data->min_width;
 
   Vminibuf_scroll_window = data->minibuf_scroll_window;
   minibuf_selected_window = data->minibuf_selected_window;
@@ -6598,7 +6690,6 @@ redirection (see `redirect-frame-focus').  */)
   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;
 
@@ -6608,13 +6699,13 @@ redirection (see `redirect-frame-focus').  */)
   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;
+  data = ALLOCATE_PSEUDOVECTOR (struct save_window_data, frame_cols,
+                              PVEC_WINDOW_CONFIGURATION);
 
-  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->frame_cols = FRAME_COLS (f);
+  data->frame_lines = FRAME_LINES (f);
+  data->frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
+  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);
@@ -6622,8 +6713,8 @@ redirection (see `redirect-frame-focus').  */)
   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);
+  data->min_height = window_min_height;
+  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++)
@@ -6643,7 +6734,7 @@ 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 ...)  */)
+usage: (save-window-excursion BODY...)  */)
      (args)
      Lisp_Object args;
 {
@@ -6897,7 +6988,7 @@ Fourth parameter HORIZONTAL-TYPE is currently unused.  */)
        vertical_type = Qnil;
     }
 
-  if (!(EQ (vertical_type, Qnil)
+  if (!(NILP (vertical_type)
        || EQ (vertical_type, Qleft)
        || EQ (vertical_type, Qright)
        || EQ (vertical_type, Qt)))
@@ -7080,11 +7171,12 @@ 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)))
+  if (MINI_WINDOW_P (w)
+      || (WINDOWP (selected_window) /* Can be nil in corner cases.  */
+         && (w == XWINDOW (selected_window)
+             || (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;
@@ -7129,11 +7221,11 @@ compare_window_configurations (c1, c2, ignore_positions)
   sw1 = XVECTOR (d1->saved_windows);
   sw2 = XVECTOR (d2->saved_windows);
 
-  if (! EQ (d1->frame_cols, d2->frame_cols))
+  if (d1->frame_cols != d2->frame_cols)
     return 0;
-  if (! EQ (d1->frame_lines, d2->frame_lines))
+  if (d1->frame_lines != d2->frame_lines)
     return 0;
-  if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
+  if (d1->frame_menu_bar_lines != d2->frame_menu_bar_lines)
     return 0;
   if (! EQ (d1->selected_frame, d2->selected_frame))
     return 0;
@@ -7155,9 +7247,9 @@ compare_window_configurations (c1, c2, ignore_positions)
      if everything else compares equal.  */
   if (! EQ (d1->focus_frame, d2->focus_frame))
     return 0;
-  if (! EQ (d1->min_width, d2->min_width))
+  if (d1->min_width != d2->min_width)
     return 0;
-  if (! EQ (d1->min_height, d2->min_height))
+  if (d1->min_height != d2->min_height)
     return 0;
 
   /* Verify that the two confis have the same number of windows.  */
@@ -7466,6 +7558,15 @@ by `display-buffer'.  The value is in line units.
 If there is only one window, it is split regardless of this value.  */);
   split_height_threshold = 500;
 
+  DEFVAR_LISP ("split-window-preferred-function",
+              &Vsplit_window_preferred_function,
+              doc: /* Function to use to split a window.
+This is used by `display-buffer' to allow the user to choose whether
+to split windows horizontally or vertically or some mix of the two.
+It is called with a window as single argument and should split it in two
+and return the new window.  */);
+  Vsplit_window_preferred_function = intern ("split-window");
+
   DEFVAR_INT ("window-min-height", &window_min_height,
              doc: /* *Delete any window less than this tall (including its mode line).
 The value is in line units. */);
@@ -7502,6 +7603,7 @@ The selected frame is the one whose configuration has changed.  */);
   defsubr (&Swindow_buffer);
   defsubr (&Swindow_height);
   defsubr (&Swindow_width);
+  defsubr (&Swindow_full_width_p);
   defsubr (&Swindow_hscroll);
   defsubr (&Sset_window_hscroll);
   defsubr (&Swindow_redisplay_end_trigger);