(window_scroll): When scrolling forward and point is
[bpt/emacs.git] / src / window.c
index 014cd3c..c5360a8 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985, 86, 87, 93, 94, 95, 96 Free Software Foundation, Inc.
+   Copyright (C) 1985,86,87,93,94,95,96,1997 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "disptab.h"
 #include "keyboard.h"
+#include "blockinput.h"
 
 Lisp_Object Qwindowp, Qwindow_live_p;
 
@@ -111,8 +112,21 @@ static int sequence_number;
 /* Nonzero after init_window_once has finished.  */
 static int window_initialized;
 
+/* Hook to run when window config changes.  */
+Lisp_Object Qwindow_configuration_change_hook;
+Lisp_Object Vwindow_configuration_change_hook;
+
+/* Nonzero means scroll commands try to put point
+   at the same screen height as previously.  */
+static int scroll_preserve_screen_position;
+
+/* Nonzero means we can split a frame even if it is "unsplittable".  */
+static int inhibit_frame_unsplittable;
+
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
+extern int scroll_margin;
+
 extern Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
 \f
 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0,
@@ -247,8 +261,17 @@ POS defaults to point; WINDOW, to the selected window.")
        return Qnil;
 
       /* If that info is not correct, calculate afresh */
+      /* BUG FIX for the 7th arg (TOHPOS).
+
+        '0' is harmless, however, ' - (1 << (BITS_PER_SHORT - 1))' is
+        more appropriate here.  In case of HSCROLL > 0, this can avoid
+        needless calculation done until (HPOS == 0).
+
+        We want to determine if the position POSINT is in HEIGHT or
+        not.  We don't have to do calculation until (HPOS == 0).  We
+        can stop it when VPOS goes beyond HEIGHT.  */
       posval = *compute_motion (top, 0, (hscroll ? 1 - hscroll : 0), 0,
-                               posint, height, 0,
+                               posint, height, - (1 << (BITS_PER_SHORT - 1)),
                                window_internal_width (w) - 1,
                                hscroll, 0, w);
 
@@ -434,7 +457,7 @@ If they are on the border between WINDOW and its right sibling,\n\
       return Qnil;
 
     case 1:                    /* In text part of window. */
-      return Fcons (x, y);
+      return Fcons (make_number (x), make_number (y));
 
     case 2:                    /* In mode line of window. */
       return Qmode_line;
@@ -770,6 +793,18 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   "Remove WINDOW from the display.  Default is selected window.")
   (window)
      register Lisp_Object window;
+{
+  delete_window (window);
+
+  if (! NILP (Vwindow_configuration_change_hook)
+      && ! NILP (Vrun_hooks))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
+  return Qnil;
+}
+
+delete_window (window)
+     register Lisp_Object window;
 {
   register Lisp_Object tem, parent, sib;
   register struct window *p;
@@ -788,7 +823,7 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
   if (NILP (p->buffer)
       && NILP (p->hchild)
       && NILP (p->vchild))
-    return Qnil;
+    return;
 
   parent = p->parent;
   if (NILP (parent))
@@ -895,8 +930,6 @@ DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "",
 
   /* Mark this window as deleted.  */
   p->buffer = p->hchild = p->vchild = Qnil;
-
-  return Qnil;
 }
 \f
 
@@ -1319,7 +1352,11 @@ window_loop (type, obj, mini, frames)
        switch (type)
          {
          case GET_BUFFER_WINDOW:
-           if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj))
+           if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)
+               /* Don't find any minibuffer window
+                  except the one that is currently in use.  */
+               && (MINI_WINDOW_P (XWINDOW (w))
+                   ? EQ (w, minibuf_window) : 1))
              return w;
            break;
 
@@ -1560,13 +1597,14 @@ value is reasonable when this function is called.")
       /* This computation used to temporarily move point, but that can
         have unwanted side effects due to text properties.  */
       pos = *vmotion (startpos, -top, w);
+
       Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
       w->start_at_line_beg = ((pos.bufpos == BEGV
-                              || FETCH_CHAR (pos.bufpos - 1) == '\n') ? Qt
+                              || FETCH_BYTE (pos.bufpos - 1) == '\n') ? Qt
                              : Qnil);
       /* We need to do this, so that the window-scroll-functions
         get called.  */
-      w->force_start = Qt;
+      w->optional_new_start = Qt;
 
       set_buffer_internal (obuf);
     }
@@ -1697,9 +1735,11 @@ set_window_height (window, height, nodelete)
 
   if (!nodelete
       && ! NILP (w->parent)
-      && height < window_min_height)
+      && (MINI_WINDOW_P (w)
+         ? height < 1
+         : height < window_min_height))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
@@ -1763,7 +1803,7 @@ set_window_width (window, width, nodelete)
 
   if (!nodelete && width < window_min_width && !NILP (w->parent))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
@@ -1854,6 +1894,9 @@ BUFFER can be a buffer or buffer name.")
 
   if (EQ (window, selected_window))
     XBUFFER (w->buffer)->last_selected_window = window;
+  if (INTEGERP (XBUFFER (buffer)->display_count))
+    XSETINT (XBUFFER (buffer)->display_count,
+            XINT (XBUFFER (buffer)->display_count) + 1);
 
   XSETFASTINT (w->window_end_pos, 0);
   w->window_end_valid = Qnil;
@@ -1887,6 +1930,10 @@ BUFFER can be a buffer or buffer name.")
     run_hook_with_args_2 (Qwindow_scroll_functions, window,
                          Fmarker_position (w->start));
 
+  if (! NILP (Vwindow_configuration_change_hook)
+      && ! NILP (Vrun_hooks))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   unbind_to (count, Qnil);
 
   return Qnil;
@@ -1980,9 +2027,9 @@ display_buffer_1 (window)
 }
 
 DEFUN ("special-display-p", Fspecial_display_p, Sspecial_display_p, 1, 1, 0,
-  "Returns non-nil if BUFFER-NAME would use a special display function.
-The value is actually t if the frame should be called with default frame
-parameters, and a list of frame parameters if they were specified.
+  "Returns non-nil if a buffer named BUFFER-NAME would be created specially.\n\
+The value is actually t if the frame should be called with default frame\n\
+parameters, and a list of frame parameters if they were specified.\n\
 See `special-display-buffer-names', and `special-display-regexps'.")
   (buffer_name)
      Lisp_Object buffer_name;
@@ -2014,7 +2061,7 @@ See `special-display-buffer-names', and `special-display-regexps'.")
 }  
 
 DEFUN ("same-window-p", Fsame_window_p, Ssame_window_p, 1, 1, 0,
-  "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.
+  "Returns non-nil if a new buffer named BUFFER-NAME would use the same window.\n\
 See `same-window-buffer-names' and `same-window-regexps'.")
   (buffer_name)
      Lisp_Object buffer_name;
@@ -2046,7 +2093,7 @@ See `same-window-buffer-names' and `same-window-regexps'.")
 }
 
 DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
-       "bDisplay buffer: \nP",
+     "BDisplay buffer: \nP",   /* Use B so the default is (other-buffer).  */
   "Make BUFFER appear in some window but don't select it.\n\
 BUFFER can be a buffer or a buffer name.\n\
 If BUFFER is shown already in some window, just use that one,\n\
@@ -2175,13 +2222,20 @@ buffer names are handled.")
              && window_height (window) >= window_min_height << 1)
            window = Fsplit_window (window, Qnil, Qnil);
          /* If Fget_lru_window returned nil, try other approaches.  */
+
          /* Try visible frames first.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, Qvisible);
          if (NILP (window))
            window = Fget_largest_window (Qvisible);
          /* If that didn't work, try iconified frames.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, make_number (0));
          if (NILP (window))
            window = Fget_largest_window (make_number (0));
          /* Try invisible frames.  */
+         if (NILP (window))
+           window = Fget_buffer_window (buffer, Qt);
          if (NILP (window))
            window = Fget_largest_window (Qt);
          /* As a last resort, make a new frame.  */
@@ -2196,15 +2250,19 @@ buffer names are handled.")
            other = lower = XWINDOW (window)->next, upper = window;
          if (!NILP (other)
              /* Check that OTHER and WINDOW are vertically arrayed.  */
-             && XWINDOW (other)->top != XWINDOW (window)->top
-             && XWINDOW (other)->height > XWINDOW (window)->height)
+             && !EQ (XWINDOW (other)->top, XWINDOW (window)->top)
+             && (XFASTINT (XWINDOW (other)->height)
+                 > XFASTINT (XWINDOW (window)->height)))
            {
-             int total = XWINDOW (other)->height + XWINDOW (window)->height;
+             int total = (XFASTINT (XWINDOW (other)->height)
+                          + XFASTINT (XWINDOW (window)->height));
              Lisp_Object old_selected_window;
              old_selected_window = selected_window;
 
              selected_window = upper;
-             change_window_height (total / 2 - XWINDOW (upper)->height, 0);
+             change_window_height ((total / 2
+                                    - XFASTINT (XWINDOW (upper)->height)),
+                                   0);
              selected_window = old_selected_window;
            }
        }
@@ -2224,6 +2282,8 @@ temp_output_buffer_show (buf)
   register Lisp_Object window;
   register struct window *w;
 
+  XBUFFER (buf)->directory = current_buffer->directory;
+
   Fset_buffer (buf);
   BUF_SAVE_MODIFF (XBUFFER (buf)) = MODIFF;
   BEGV = BEG;
@@ -2342,8 +2402,6 @@ and put SIZE columns in the first of the pair.")
 
   if (MINI_WINDOW_P (o))
     error ("Attempt to split minibuffer window");
-  else if (FRAME_NO_SPLIT_P (fo))
-    error ("Attempt to split unsplittable frame");
 
   check_min_window_sizes ();
 
@@ -2397,8 +2455,6 @@ and put SIZE columns in the first of the pair.")
   p->parent = o->parent;
   p->buffer = Qt;
 
-  Fset_window_buffer (new, o->buffer);
-
   /* Apportion the available frame space among the two new windows */
 
   if (!NILP (horflag))
@@ -2418,6 +2474,8 @@ and put SIZE columns in the first of the pair.")
       XSETFASTINT (p->top, XFASTINT (o->top) + size_int);
     }
 
+  Fset_window_buffer (new, o->buffer);
+
   return new;
 }
 \f
@@ -2429,6 +2487,10 @@ From program, optional second arg non-nil means grow sideways ARG columns.")
 {
   CHECK_NUMBER (arg, 0);
   change_window_height (XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
@@ -2440,6 +2502,10 @@ From program, optional second arg non-nil means shrink sideways arg columns.")
 {
   CHECK_NUMBER (arg, 0);
   change_window_height (-XINT (arg), !NILP (side));
+
+  if (! NILP (Vwindow_configuration_change_hook))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return Qnil;
 }
 
@@ -2486,6 +2552,8 @@ change_window_height (delta, widthflag)
   register int (*setsizefun) () = (widthflag
                                   ? set_window_width
                                   : set_window_height);
+  int maximum;
+  Lisp_Object next, prev;
 
   check_min_window_sizes ();
 
@@ -2527,29 +2595,78 @@ change_window_height (delta, widthflag)
 
   if (*sizep + delta < MINSIZE (window))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
   if (delta == 0)
     return;
 
-  if (!NILP (p->next)
-      && (*sizefun) (p->next) - delta >= MINSIZE (p->next))
-    {
-      (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0);
-      (*setsizefun) (window, *sizep + delta, 0);
-      CURBEG (p->next) += delta;
-      /* This does not change size of p->next,
-        but it propagates the new top edge to its children */
-      (*setsizefun) (p->next, (*sizefun) (p->next), 0);
-    }
-  else if (!NILP (p->prev)
-          && (*sizefun) (p->prev) - delta >= MINSIZE (p->prev))
+  /* Find the total we can get from other siblings.  */
+  maximum = 0;
+  for (next = p->next; ! NILP (next); next = XWINDOW (next)->next)
+    maximum += (*sizefun) (next) - MINSIZE (next);
+  for (prev = p->prev; ! NILP (prev); prev = XWINDOW (prev)->prev)
+    maximum += (*sizefun) (prev) - MINSIZE (prev);
+
+  /* If we can get it all from them, do so.  */
+  if (delta <= maximum)
     {
-      (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0);
-      CURBEG (window) -= delta;
-      (*setsizefun) (window, *sizep + delta, 0);
+      Lisp_Object first_unaffected;
+      Lisp_Object first_affected;
+
+      next = p->next;
+      prev = p->prev;
+      first_affected = window;
+      /* Look at one sibling at a time,
+        moving away from this window in both directions alternately,
+        and take as much as we can get without deleting that sibling.  */
+      while (delta != 0)
+       {
+         if (delta == 0)
+           break;
+         if (! NILP (next))
+           {
+             int this_one = (*sizefun) (next) - MINSIZE (next);
+             if (this_one > delta)
+               this_one = delta;
+
+             (*setsizefun) (next, (*sizefun) (next) - this_one, 0);
+             (*setsizefun) (window, *sizep + this_one, 0);
+
+             delta -= this_one;
+             next = XWINDOW (next)->next;
+           }
+         if (delta == 0)
+           break;
+         if (! NILP (prev))
+           {
+             int this_one = (*sizefun) (prev) - MINSIZE (prev);
+             if (this_one > delta)
+               this_one = delta;
+
+             first_affected = prev;
+
+             (*setsizefun) (prev, (*sizefun) (prev) - this_one, 0);
+             (*setsizefun) (window, *sizep + this_one, 0);
+
+             delta -= this_one;
+             prev = XWINDOW (prev)->prev;
+           }
+       }
+
+      /* Now recalculate the edge positions of all the windows affected,
+        based on the new sizes.  */
+      first_unaffected = next;
+      prev = first_affected;
+      for (next = XWINDOW (prev)->next; ! EQ (next, first_unaffected);
+          prev = next, next = XWINDOW (next)->next)
+       {
+         CURBEG (next) = CURBEG (prev) + (*sizefun) (prev);
+         /* This does not change size of NEXT,
+            but it propagates the new top edge to its children */
+         (*setsizefun) (next, (*sizefun) (next), 0);
+       }
     }
   else
     {
@@ -2632,12 +2749,14 @@ window_internal_width (w)
 }
 
 
-/* Scroll contents of window WINDOW up N lines.  */
+/* Scroll contents of window WINDOW up N lines.
+   If WHOLE is nonzero, it means scroll N screenfuls instead.  */
 
-void
-window_scroll (window, n, noerror)
+static void
+window_scroll (window, n, whole, noerror)
      Lisp_Object window;
      int n;
+     int whole;
      int noerror;
 {
   register struct window *w = XWINDOW (window);
@@ -2647,10 +2766,17 @@ window_scroll (window, n, noerror)
   register Lisp_Object tem;
   int lose;
   Lisp_Object bolp, nmoved;
+  int startpos;
+  struct position posit;
+  int original_vpos;
 
-  /* Always set force_start so that redisplay_window will run
-     the window-scroll-functions.  */
-  w->force_start = Qt;
+  startpos = marker_position (w->start);
+
+  posit = *compute_motion (startpos, 0, 0, 0,
+                          PT, ht, 0,
+                          window_internal_width (w), XINT (w->hscroll),
+                          0, w);
+  original_vpos = posit.vpos;
 
   XSETFASTINT (tem, PT);
   tem = Fpos_visible_in_window_p (tem, window);
@@ -2658,11 +2784,10 @@ window_scroll (window, n, noerror)
   if (NILP (tem))
     {
       Fvertical_motion (make_number (- (ht / 2)), window);
-      XSETFASTINT (tem, PT);
-      Fset_marker (w->start, tem, w->buffer);
+      startpos = PT;
     }
 
-  SET_PT (marker_position (w->start));
+  SET_PT (startpos);
   lose = n < 0 && PT == BEGV;
   Fvertical_motion (make_number (n), window);
   pos = PT;
@@ -2679,21 +2804,79 @@ window_scroll (window, n, noerror)
 
   if (pos < ZV)
     {
+      int this_scroll_margin = scroll_margin;
+
+      /* Don't use a scroll margin that is negative or too large.  */
+      if (this_scroll_margin < 0)
+       this_scroll_margin = 0;
+
+      if (XINT (w->height) < 4 * scroll_margin)
+       this_scroll_margin = XINT (w->height) / 4;
+
       set_marker_restricted (w->start, make_number (pos), w->buffer);
       w->start_at_line_beg = bolp;
       w->update_mode_line = Qt;
       XSETFASTINT (w->last_modified, 0);
       XSETFASTINT (w->last_overlay_modified, 0);
-      if (pos > opoint)
-       SET_PT (pos);
-      if (n < 0)
+      /* Set force_start so that redisplay_window will run
+        the window-scroll-functions.  */
+      w->force_start = Qt;
+
+      if (whole && scroll_preserve_screen_position)
+       {
+         SET_PT (pos);
+         Fvertical_motion (make_number (original_vpos), window);
+       }
+      /* If we scrolled forward, put point enough lines down
+        that it is outside the scroll margin.  */
+      else if (n > 0)
+       {
+         int top_margin;
+
+         if (this_scroll_margin > 0)
+           {
+             SET_PT (pos);
+             Fvertical_motion (make_number (this_scroll_margin), window);
+             top_margin = PT;
+           }
+         else
+           top_margin = pos;
+
+         if (top_margin <= opoint)
+           SET_PT (opoint);
+         else if (scroll_preserve_screen_position)
+           {
+             SET_PT (pos);
+             Fvertical_motion (make_number (original_vpos), window);
+           }
+         else
+           SET_PT (top_margin);
+       }
+      else if (n < 0)
        {
+         int bottom_margin;
+
+         /* If we scrolled backward, put point near the end of the window
+            but not within the scroll margin.  */
          SET_PT (pos);
-         tem = Fvertical_motion (make_number (ht), window);
-         if (PT > opoint || XFASTINT (tem) < ht)
+         tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
+         if (XFASTINT (tem) == ht - this_scroll_margin)
+           bottom_margin = PT;
+         else
+           bottom_margin = PT + 1;
+
+         if (bottom_margin > opoint)
            SET_PT (opoint);
          else
-           Fvertical_motion (make_number (-1), window);
+           {
+             if (scroll_preserve_screen_position)
+               {
+                 SET_PT (pos);
+                 Fvertical_motion (make_number (original_vpos), window);
+               }
+             else
+               Fvertical_motion (make_number (-1), window);
+           }
        }
     }
   else
@@ -2728,13 +2911,13 @@ scroll_command (n, direction)
   defalt = direction * (defalt < 1 ? 1 : defalt);
 
   if (NILP (n))
-    window_scroll (selected_window, defalt, 0);
+    window_scroll (selected_window, defalt, 1, 0);
   else if (EQ (n, Qminus))
-    window_scroll (selected_window, - defalt, 0);
+    window_scroll (selected_window, - defalt, 1, 0);
   else
     {
       n = Fprefix_numeric_value (n);
-      window_scroll (selected_window, XINT (n) * direction, 0);
+      window_scroll (selected_window, XINT (n) * direction, 0, 0);
     }
 
   unbind_to (count, Qnil);
@@ -2838,15 +3021,15 @@ showing that buffer, popping the buffer up if necessary.")
   SET_PT (marker_position (w->pointm));
 
   if (NILP (arg))
-    window_scroll (window, defalt, 1);
+    window_scroll (window, defalt, 1, 1);
   else if (EQ (arg, Qminus))
-    window_scroll (window, -defalt, 1);
+    window_scroll (window, -defalt, 1, 1);
   else
     {
       if (CONSP (arg))
        arg = Fcar (arg);
       CHECK_NUMBER (arg, 0);
-      window_scroll (window, XINT (arg), 1);
+      window_scroll (window, XINT (arg), 0, 1);
     }
 
   Fset_marker (w->pointm, make_number (PT), Qnil);
@@ -2927,7 +3110,7 @@ redraws with point in the center of the current window.")
 
   Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
   w->start_at_line_beg = ((pos.bufpos == BEGV
-                          || FETCH_CHAR (pos.bufpos - 1) == '\n')
+                          || FETCH_BYTE (pos.bufpos - 1) == '\n')
                          ? Qt : Qnil);
   w->force_start = Qt;
 
@@ -3033,6 +3216,7 @@ by `current-window-configuration' (which see).")
   Lisp_Object new_current_buffer;
   Lisp_Object frame;
   FRAME_PTR f;
+  int old_point = -1;
 
   while (!WINDOW_CONFIGURATIONP (configuration))
     {
@@ -3046,6 +3230,11 @@ by `current-window-configuration' (which see).")
   new_current_buffer = data->current_buffer;
   if (NILP (XBUFFER (new_current_buffer)->name))
     new_current_buffer = Qnil;
+  else
+    {
+      if (XBUFFER (new_current_buffer) == current_buffer)
+       old_point = PT;
+    }
 
   frame = XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->frame;
   f = XFRAME (frame);
@@ -3066,6 +3255,10 @@ by `current-window-configuration' (which see).")
       int previous_frame_width =  FRAME_WIDTH  (f);
       int previous_frame_menu_bar_lines = FRAME_MENU_BAR_LINES (f);
 
+      /* The mouse highlighting code could get screwed up
+        if it runs during this.  */
+      BLOCK_INPUT;
+
       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);
@@ -3197,6 +3390,8 @@ by `current-window-configuration' (which see).")
 
       FRAME_ROOT_WINDOW (f) = data->root_window;
       Fselect_window (data->current_window);
+      XBUFFER (XWINDOW (selected_window)->buffer)->last_selected_window
+       = selected_window;
 
       if (NILP (data->focus_frame)
          || (FRAMEP (data->focus_frame)
@@ -3219,6 +3414,8 @@ by `current-window-configuration' (which see).")
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
        x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
 #endif
+
+      UNBLOCK_INPUT;
     }
 
   /* Restore the minimum heights recorded in the configuration.  */
@@ -3234,9 +3431,22 @@ by `current-window-configuration' (which see).")
     do_switch_frame (data->selected_frame, Qnil, 0);
 
   if (!NILP (new_current_buffer))
-    Fset_buffer (new_current_buffer);
+    {
+      Fset_buffer (new_current_buffer);
+
+      /* If the buffer that is current now is the same
+        that was current before setting the window configuration,
+        don't alter its PT.  */
+      if (old_point >= 0)
+       SET_PT (old_point);
+    }
 
   Vminibuf_scroll_window = data->minibuf_scroll_window;
+
+  if (! NILP (Vwindow_configuration_change_hook)
+      && ! NILP (Vrun_hooks))
+    call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+
   return (Qnil);
 }
 
@@ -3314,7 +3524,8 @@ save_window_save (window, vector, i)
          if (EQ (window, selected_window))
            {
              p->pointm = Fmake_marker ();
-             Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
+             Fset_marker (p->pointm,
+                          make_number (BUF_PT (XBUFFER (w->buffer))),
                           w->buffer);
            }
          else
@@ -3353,8 +3564,8 @@ save_window_save (window, vector, i)
   return i;
 }
 
-DEFUN ("current-window-configuration",
-       Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0,
+DEFUN ("current-window-configuration", Fcurrent_window_configuration,
+  Scurrent_window_configuration, 0, 1, 0,
   "Return an object representing the current window configuration of FRAME.\n\
 If FRAME is nil or omitted, use the selected frame.\n\
 This describes the number of windows, their sizes and current buffers,\n\
@@ -3443,6 +3654,10 @@ init_window_once ()
 
 syms_of_window ()
 {
+  staticpro (&Qwindow_configuration_change_hook);
+  Qwindow_configuration_change_hook
+    = intern ("window-configuration-change-hook");
+
   Qwindowp = intern ("windowp");
   staticpro (&Qwindowp);
 
@@ -3499,7 +3714,12 @@ There are two ways to use a list as an element:\n\
 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
 In the latter case, FUNCTION is called with BUFFER as the first argument,\n\
 followed by OTHER-ARGS--it can display BUFFER in any way it likes.\n\
-All this is done by the function found in `special-display-function'.");
+All this is done by the function found in `special-display-function'.\n\
+\n\
+If this variable appears \"not to work\", because you add a name to it\n\
+but that buffer still appears in the selected window, look at the\n\
+values of `same-window-buffer-names' and `same-window-regexps'.\n\
+Those variables take precedence over this one.");
   Vspecial_display_buffer_names = Qnil;
 
   DEFVAR_LISP ("special-display-regexps", &Vspecial_display_regexps,
@@ -3514,7 +3734,12 @@ There are two ways to use a list as an element:\n\
 In the first case, FRAME-PARAMETERS are used to create the frame.\n\
 In the latter case, FUNCTION is called with the buffer as first argument,\n\
 followed by OTHER-ARGS--it can display the buffer in any way it likes.\n\
-All this is done by the function found in `special-display-function'.");
+All this is done by the function found in `special-display-function'.\n\
+\n\
+If this variable appears \"not to work\", because you add a regexp to it\n\
+but the matching buffers still appear in the selected window, look at the\n\
+values of `same-window-buffer-names' and `same-window-regexps'.\n\
+Those variables take precedence over this one.");
   Vspecial_display_regexps = Qnil;
 
   DEFVAR_LISP ("special-display-function", &Vspecial_display_function,
@@ -3577,6 +3802,17 @@ If there is only one window, it is split regardless of this value.");
     "*Delete any window less than this wide.");
   window_min_width = 10;
 
+  DEFVAR_BOOL ("scroll-preserve-screen-position",
+              &scroll_preserve_screen_position,
+    "*Nonzero means scroll commands move point to keep its screen line unchanged.");
+  scroll_preserve_screen_position = 0;
+
+  DEFVAR_LISP ("window-configuration-change-hook",
+              &Vwindow_configuration_change_hook,
+    "Functions to call when window configuration changes.\n\
+The selected frae is the one whose configuration has changed.");
+  Vwindow_configuration_change_hook = Qnil;
+
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);