]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Merged from
[gnu-emacs] / src / window.c
index 520d5ae8eaabdce040290b9f7bcb8677b3adee9b..58ab3ee14a0ccbd9cde6681667e4b02c26c10cac 100644 (file)
@@ -1,7 +1,7 @@
 /* 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 Free Software Foundation, Inc.
+                 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -67,7 +67,7 @@ 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 void enlarge_window P_ ((Lisp_Object, 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,
@@ -212,6 +212,10 @@ Lisp_Object Vwindow_configuration_change_hook;
 
 Lisp_Object Vscroll_preserve_screen_position;
 
+/* Incremented by 1 whenever a window is deleted.  */
+
+int window_deletion_count;
+
 #if 0 /* This isn't used anywhere.  */
 /* Nonzero means we can split a frame even if it is "unsplittable".  */
 static int inhibit_frame_unsplittable;
@@ -1335,7 +1339,7 @@ delete_window (window)
     CHECK_WINDOW (window);
   p = XWINDOW (window);
 
-  /* It's okay to delete an already-deleted window.  */
+  /* It's a no-op to delete an already-deleted window.  */
   if (NILP (p->buffer)
       && NILP (p->hchild)
       && NILP (p->vchild))
@@ -1399,6 +1403,9 @@ delete_window (window)
       }
   }
 
+  /* Now we know we can delete this one.  */
+  window_deletion_count++;
+
   tem = p->buffer;
   /* tem is null for dummy parent windows
      (which have inferiors but not any contents themselves) */
@@ -1824,7 +1831,7 @@ DEFUN ("other-window", Fother_window, Sother_window, 1, 2, "p",
 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.  */)
+argument ALL-FRAMES has the same meaning as in `next-window', which see.  */)
      (arg, all_frames)
      Lisp_Object arg, all_frames;
 {
@@ -1964,7 +1971,7 @@ window_loop (type, obj, mini, frames)
   GCPRO1 (windows);
   best_window = Qnil;
 
-  for (; CONSP (windows); windows = CDR (windows))
+  for (; CONSP (windows); windows = XCDR (windows))
     {
       struct window *w;
 
@@ -1998,11 +2005,13 @@ window_loop (type, obj, mini, frames)
            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))
+           /* `obj' is an integer encoding a bitvector.
+              `obj & 1' means consider only full-width windows.
+              `obj & 2' means consider also dedicated windows. */
+           if (((XINT (obj) & 1) && !WINDOW_FULL_WIDTH_P (w))
+               || (!(XINT (obj) & 2) && EQ (w->dedicated, Qt))
+               /* Minibuffer windows are always ignored.  */
+               || MINI_WINDOW_P (w))
              break;
            if (NILP (best_window)
                || (XFASTINT (XWINDOW (best_window)->use_time)
@@ -2053,9 +2062,9 @@ window_loop (type, obj, mini, frames)
            break;
 
          case GET_LARGEST_WINDOW:
-           {
+           { /* nil `obj' means to ignore dedicated windows.  */
              /* Ignore dedicated windows and minibuffers.  */
-             if (MINI_WINDOW_P (w) || EQ (w->dedicated, Qt))
+             if (MINI_WINDOW_P (w) || (NILP (obj) && EQ (w->dedicated, Qt)))
                break;
 
              if (NILP (best_window))
@@ -2149,43 +2158,47 @@ check_all_windows ()
   window_loop (CHECK_ALL_WINDOWS, Qnil, 1, Qt);
 }
 
-DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0,
+DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0,
        doc: /* Return the window least recently selected or used for display.
 Return a full-width window if possible.
 A minibuffer window is never a candidate.
-A dedicated window is never a candidate, so if all windows are dedicated,
-the value is nil.
+A dedicated window is never a candidate, unless DEDICATED is non-nil,
+  so if all windows are dedicated, the value is nil.
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
 If FRAME is t, search all frames.
 If FRAME is nil, search only the selected frame.
 If FRAME is a frame, search only that frame.  */)
-     (frame)
-     Lisp_Object frame;
+  (frame, dedicated)
+     Lisp_Object frame, dedicated;
 {
   register Lisp_Object w;
   /* First try for a window that is full-width */
-  w = window_loop (GET_LRU_WINDOW, Qt, 0, frame);
+  w = window_loop (GET_LRU_WINDOW,
+                  NILP (dedicated) ? make_number (1) : make_number (3),
+                  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);
+  return window_loop (GET_LRU_WINDOW,
+                     NILP (dedicated) ? make_number (0) : make_number (2),
+                     0, frame);
 }
 
-DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0,
+DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0,
        doc: /* Return the largest window in area.
 A minibuffer window is never a candidate.
-A dedicated window is never a candidate, so if all windows are dedicated,
-the value is nil.
+A dedicated window is never a candidate unless DEDICATED is non-nil,
+  so if all windows are dedicated, the value is nil.
 If optional argument FRAME is `visible', search all visible frames.
 If FRAME is 0, search all visible and iconified frames.
 If FRAME is t, search all frames.
 If FRAME is nil, search only the selected frame.
 If FRAME is a frame, search only that frame.  */)
-     (frame)
-     Lisp_Object frame;
+    (frame, dedicated)
+     Lisp_Object frame, dedicated;
 {
-  return window_loop (GET_LARGEST_WINDOW, Qnil, 0,
+  return window_loop (GET_LARGEST_WINDOW, dedicated, 0,
                      frame);
 }
 
@@ -3505,15 +3518,17 @@ displayed.  */)
       if (FRAME_NO_SPLIT_P (NILP (frames) ? f : last_nonminibuf_frame))
        {
          /* Try visible frames first.  */
-         window = Fget_largest_window (Qvisible);
+         window = Fget_largest_window (Qvisible, Qt);
          /* If that didn't work, try iconified frames.  */
          if (NILP (window))
-           window = Fget_largest_window (make_number (0));
+           window = Fget_largest_window (make_number (0), Qt);
+#if 0     /* Don't try windows on other displays.  */
          if (NILP (window))
-           window = Fget_largest_window (Qt);
+           window = Fget_largest_window (Qt, Qt);
+#endif
        }
       else
-       window = Fget_largest_window (frames);
+       window = Fget_largest_window (frames, Qt);
 
       /* If we got a tall enough full-width window that can be split,
         split it.  */
@@ -3526,7 +3541,7 @@ displayed.  */)
        {
          Lisp_Object upper, lower, other;
 
-         window = Fget_lru_window (frames);
+         window = Fget_lru_window (frames, Qt);
          /* If the LRU window is selected, and big enough,
             and can be split, split it.  */
          if (!NILP (window)
@@ -3535,23 +3550,27 @@ displayed.  */)
                  || EQ (XWINDOW (window)->parent, Qnil))
              && window_height (window) >= window_min_height << 1)
            window = Fsplit_window (window, Qnil, Qnil);
+         else
+           window = Fget_lru_window (frames, 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);
+           window = Fget_largest_window (Qvisible, Qnil);
          /* 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.  */
+           window = Fget_largest_window (make_number (0), Qnil);
+
+#if 0     /* Don't try frames on other displays.  */
          if (NILP (window))
            window = Fget_buffer_window (buffer, Qt);
          if (NILP (window))
-           window = Fget_largest_window (Qt);
+           window = Fget_largest_window (Qt, Qnil);
+#endif
          /* As a last resort, make a new frame.  */
          if (NILP (window))
            window = Fframe_selected_window (call0 (Vpop_up_frame_function));
@@ -3573,12 +3592,12 @@ displayed.  */)
                           + XFASTINT (XWINDOW (window)->total_lines));
              enlarge_window (upper,
                              total / 2 - XFASTINT (XWINDOW (upper)->total_lines),
-                             0, 0);
+                             0);
            }
        }
     }
   else
-    window = Fget_lru_window (Qnil);
+    window = Fget_lru_window (Qnil, Qnil);
 
   Fset_window_buffer (window, buffer, Qnil);
   return display_buffer_1 (window);
@@ -3650,7 +3669,7 @@ temp_output_buffer_show (buf)
 #endif
   set_buffer_internal (old);
 
-  if (!EQ (Vtemp_buffer_show_function, Qnil))
+  if (!NILP (Vtemp_buffer_show_function))
     call1 (Vtemp_buffer_show_function, buf);
   else
     {
@@ -3864,20 +3883,18 @@ See Info node `(elisp)Splitting Windows' for more details and examples.*/)
   return new;
 }
 \f
-DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "p",
+DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "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;
+If HORIZONTAL is non-nil, enlarge horizontally instead of vertically.
+This function can delete windows, even the second window, if they get
+too small.  */)
+     (arg, horizontal)
+     Lisp_Object arg, horizontal;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, XINT (arg), !NILP (side),
-                 !NILP (preserve_before));
+  enlarge_window (selected_window, XINT (arg), !NILP (horizontal));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3885,20 +3902,16 @@ siblings to the right or below are changed.  */)
   return Qnil;
 }
 
-DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "p",
+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.
-
-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
+Interactively, if an argument is not given, make the window one line smaller.  Only
 siblings to the right or below are changed.  */)
-     (arg, side, preserve_before)
-     register Lisp_Object arg, side, preserve_before;
+     (arg, side)
+     Lisp_Object arg, side;
 {
   CHECK_NUMBER (arg);
-  enlarge_window (selected_window, -XINT (arg), !NILP (side),
-                 !NILP (preserve_before));
+  enlarge_window (selected_window, -XINT (arg), !NILP (side));
 
   if (! NILP (Vwindow_configuration_change_hook))
     call1 (Vrun_hooks, Qwindow_configuration_change_hook);
@@ -3924,40 +3937,40 @@ window_width (window)
 
 
 #define CURBEG(w) \
-  *(widthflag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
+  *(horiz_flag ? &(XWINDOW (w)->left_col) : &(XWINDOW (w)->top_line))
 
 #define CURSIZE(w) \
-  *(widthflag ? &(XWINDOW (w)->total_cols) : &(XWINDOW (w)->total_lines))
+  *(horiz_flag ? &(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.
+/* Enlarge WINDOW by DELTA.
+   HORIZ_FLAG nonzero means enlarge it horizontally;
+   zero means do it vertically.
 
-   If PRESERVE_BEFORE is nonzero, that means don't alter
-   the siblings to the left or above WINDOW.  */
+   Siblings of the selected window are resized to fulfill the size
+   request.  If they become too small in the process, they will be
+   deleted.  */
 
 static void
-enlarge_window (window, delta, widthflag, preserve_before)
+enlarge_window (window, delta, horiz_flag)
      Lisp_Object window;
-     int delta, widthflag, preserve_before;
+     int delta, horiz_flag;
 {
   Lisp_Object parent, next, prev;
   struct window *p;
   Lisp_Object *sizep;
   int maximum;
   int (*sizefun) P_ ((Lisp_Object))
-    = widthflag ? window_width : window_height;
+    = horiz_flag ? window_width : window_height;
   void (*setsizefun) P_ ((Lisp_Object, int, int))
-    = (widthflag ? set_window_width : set_window_height);
+    = (horiz_flag ? 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))
+  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
     error ("Window is not resizable");
 
   /* Find the parent of the selected window.  */
@@ -3968,12 +3981,12 @@ enlarge_window (window, delta, widthflag, preserve_before)
 
       if (NILP (parent))
        {
-         if (widthflag)
+         if (horiz_flag)
            error ("No other window to side of this one");
          break;
        }
 
-      if (widthflag
+      if (horiz_flag
          ? !NILP (XWINDOW (parent)->hchild)
          : !NILP (XWINDOW (parent)->vchild))
        break;
@@ -3988,33 +4001,18 @@ enlarge_window (window, delta, widthflag, preserve_before)
 
     /* 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));
+    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),
+                                                       horiz_flag, 0, 0))
+               /* This is a minibuffer following a main window.  */
+               : !NILP (p->prev) ? ((*sizefun) (p->prev)
+                                    - window_min_size (XWINDOW (p->prev),
+                                                       horiz_flag, 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
@@ -4023,7 +4021,7 @@ enlarge_window (window, delta, widthflag, preserve_before)
       delta = maxdelta;
   }
 
-  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), widthflag, 0, 0))
+  if (XINT (*sizep) + delta < window_min_size (XWINDOW (window), horiz_flag, 0, 0))
     {
       delete_window (window);
       return;
@@ -4036,11 +4034,10 @@ enlarge_window (window, delta, widthflag, preserve_before)
   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);
+                                                   horiz_flag, 0, 0);
+  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+    maximum += (*sizefun) (prev) - window_min_size (XWINDOW (prev),
+                                                   horiz_flag, 0, 0);
 
   /* If we can get it all from them without deleting them, do so.  */
   if (delta <= maximum)
@@ -4056,13 +4053,13 @@ enlarge_window (window, delta, widthflag, preserve_before)
         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))))
+            && (!NILP (next) || !NILP (prev)))
        {
          if (! NILP (next))
            {
              int this_one = ((*sizefun) (next)
                              - window_min_size (XWINDOW (next),
-                                                widthflag, 0, &fixed_p));
+                                                horiz_flag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -4080,11 +4077,11 @@ enlarge_window (window, delta, widthflag, preserve_before)
          if (delta == 0)
            break;
 
-         if (!preserve_before && ! NILP (prev))
+         if (! NILP (prev))
            {
              int this_one = ((*sizefun) (prev)
                              - window_min_size (XWINDOW (prev),
-                                                widthflag, 0, &fixed_p));
+                                                horiz_flag, 0, &fixed_p));
              if (!fixed_p)
                {
                  if (this_one > delta)
@@ -4187,10 +4184,10 @@ enlarge_window (window, delta, widthflag, preserve_before)
          int n = 1;
 
          for (s = w->next; !NILP (s); s = XWINDOW (s)->next)
-           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
          for (s = w->prev; !NILP (s); s = XWINDOW (s)->prev)
-           if (!window_fixed_size_p (XWINDOW (s), widthflag, 0))
+           if (!window_fixed_size_p (XWINDOW (s), horiz_flag, 0))
              ++n;
 
          delta1 = n * delta;
@@ -4217,9 +4214,144 @@ enlarge_window (window, delta, widthflag, preserve_before)
   adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
 }
 
+
+/* Adjust the size of WINDOW by DELTA, moving only its trailing edge.
+   HORIZ_FLAG nonzero means adjust the width, moving the right edge.
+   zero means adjust the height, moving the bottom edge.
+
+   Following siblings of the selected window are resized to fulfill
+   the size request.  If they become too small in the process, they
+   are not deleted; instead, we signal an error.  */
+
+static void
+adjust_window_trailing_edge (window, delta, horiz_flag)
+     Lisp_Object window;
+     int delta, horiz_flag;
+{
+  Lisp_Object parent, child;
+  struct window *p;
+  Lisp_Object old_config = Fcurrent_window_configuration (Qnil);
+  int delcount = window_deletion_count;
+
+  /* Check values of window_min_width and window_min_height for
+     validity.  */
+  check_min_window_sizes ();
+
+  if (NILP (window))
+    window = Fselected_window ();
+
+  CHECK_WINDOW (window);
+
+  /* Give up if this window cannot be resized.  */
+  if (window_fixed_size_p (XWINDOW (window), horiz_flag, 1))
+    error ("Window is not resizable");
+
+  while (1)
+    {
+      p = XWINDOW (window);
+      parent = p->parent;
+
+      /* Make sure there is a following window.  */
+      if (NILP (parent)
+         && (horiz_flag ? 1
+             : NILP (XWINDOW (window)->next)))
+       {
+         Fset_window_configuration (old_config);
+         error ("No other window following this one");
+       }
+
+      /* Don't make this window too small.  */
+      if (XINT (CURSIZE (window)) + delta
+         < (horiz_flag ? window_min_width : window_min_height))
+       {
+         Fset_window_configuration (old_config);
+         error ("Cannot adjust window size as specified");
+       }
+
+      /* Clear out some redisplay caches.  */
+      XSETFASTINT (p->last_modified, 0);
+      XSETFASTINT (p->last_overlay_modified, 0);
+
+      /* Adjust this window's edge.  */
+      XSETINT (CURSIZE (window),
+              XINT (CURSIZE (window)) + delta);
+
+      /* If this window has following siblings in the desired dimension,
+        make them smaller.
+        (If we reach the top of the tree and can never do this,
+        we will fail and report an error, above.)  */
+      if (horiz_flag
+         ? !NILP (XWINDOW (parent)->hchild)
+         : !NILP (XWINDOW (parent)->vchild))
+       {
+         if (!NILP (XWINDOW (window)->next))
+           {
+              /* This may happen for the minibuffer.  In that case
+                 the window_deletion_count check below does not work.  */
+              if (XINT (CURSIZE (p->next)) - delta <= 0) 
+                {
+                  Fset_window_configuration (old_config);
+                  error ("Cannot adjust window size as specified");
+                }
+
+             XSETINT (CURBEG (p->next),
+                      XINT (CURBEG (p->next)) + delta);
+             size_window (p->next, XINT (CURSIZE (p->next)) - delta,
+                          horiz_flag, 0);
+             break;
+           }
+       }
+      else
+       /* Here we have a chain of parallel siblings, in the other dimension.
+          Change the size of the other siblings.  */
+       for (child = (horiz_flag
+                     ? XWINDOW (parent)->vchild
+                     : XWINDOW (parent)->hchild);
+            ! NILP (child);
+            child = XWINDOW (child)->next)
+         if (! EQ (child, window))
+           size_window (child, XINT (CURSIZE (child)) + delta,
+                        horiz_flag, 0);
+
+      window = parent;
+    }
+
+  /* If we made a window so small it got deleted,
+     we failed.  Report failure.  */
+  if (delcount != window_deletion_count)
+    {
+      Fset_window_configuration (old_config);
+      error ("Cannot adjust window size as specified");
+    }
+
+  /* Adjust glyph matrices. */
+  adjust_glyphs (XFRAME (WINDOW_FRAME (XWINDOW (window))));
+}
+
 #undef CURBEG
 #undef CURSIZE
 
+DEFUN ("adjust-window-trailing-edge", Fadjust_window_trailing_edge,
+       Sadjust_window_trailing_edge, 3, 3, 0,
+       doc: /* Adjust the bottom or right edge of WINDOW by DELTA.
+If HORIZONTAL is non-nil, that means adjust the width, moving the right edge.
+Otherwise, adjust the height, moving the bottom edge.
+
+Following siblings of the selected window are resized to fulfill
+the size request.  If they become too small in the process, they
+are not deleted; instead, we signal an error.  */)
+  (window, delta, horizontal)
+  Lisp_Object window, delta, horizontal;
+{
+  CHECK_NUMBER (delta);
+  adjust_window_trailing_edge (window, XINT (delta), !NILP (horizontal));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
+  return Qnil;
+}
+
 
 \f
 /***********************************************************************
@@ -4454,7 +4586,7 @@ shrink_mini_window (w)
         among the other windows.  */
       Lisp_Object window;
       XSETWINDOW (window, w);
-      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0, 0);
+      enlarge_window (window, 1 - XFASTINT (w->total_lines), 0);
     }
 }
 
@@ -5683,7 +5815,23 @@ the return value is nil.  Otherwise the value is t.  */)
   else
     {
       if (XBUFFER (new_current_buffer) == current_buffer)
-       old_point = PT;
+       /* The code further down "preserves point" by saving here PT in
+          old_point and then setting it later back into PT.  When the
+          current-selected-window and the final-selected-window both show
+          the current buffer, this suffers from the problem that the
+          current PT is the window-point of the current-selected-window,
+          while the final PT is the point of the final-selected-window, so
+          this copy from one PT to the other would end up moving the
+          window-point of the final-selected-window to the window-point of
+          the current-selected-window.  So we have to be careful which
+          point of the current-buffer we copy into old_point.  */
+       if (EQ (XWINDOW (data->current_window)->buffer, new_current_buffer)
+           && WINDOWP (selected_window)
+           && EQ (XWINDOW (selected_window)->buffer, new_current_buffer)
+           && !EQ (selected_window, data->current_window))
+         old_point = XMARKER (XWINDOW (data->current_window)->pointm)->charpos;
+       else
+         old_point = PT;
       else
        /* BUF_PT (XBUFFER (new_current_buffer)) gives us the position of
           point in new_current_buffer as of the last time this buffer was
@@ -6522,7 +6670,7 @@ 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.  */)
+optional second arg PIXELS-P means value is measured in pixels.  */)
   (window, pixels_p)
      Lisp_Object window, pixels_p;
 {
@@ -6552,7 +6700,7 @@ DEFUN ("set-window-vscroll", Fset_window_vscroll, Sset_window_vscroll,
        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.
+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.
@@ -7100,6 +7248,7 @@ The selected frame is the one whose configuration has changed.  */);
   defsubr (&Ssplit_window);
   defsubr (&Senlarge_window);
   defsubr (&Sshrink_window);
+  defsubr (&Sadjust_window_trailing_edge);
   defsubr (&Sscroll_up);
   defsubr (&Sscroll_down);
   defsubr (&Sscroll_left);