(rmail-edit-current-message, rmail-cease-edit):
[bpt/emacs.git] / src / window.c
index 1c90476..06d5fcf 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,97,1998 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -29,14 +29,17 @@ Boston, MA 02111-1307, USA.  */
 #include "termchar.h"
 #include "disptab.h"
 #include "keyboard.h"
+#include "blockinput.h"
+#include "dispextern.h"
+#ifdef HAVE_X_WINDOWS
+#include "xterm.h"
+#endif
 
 Lisp_Object Qwindowp, Qwindow_live_p;
 
-Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window ();
-Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter ();
+static struct window *decode_window P_ ((Lisp_Object));
 
-void delete_all_subwindows ();
-static struct window *decode_window();
+static Lisp_Object select_window_1 P_ ((Lisp_Object, int));
 
 /* This is the window in which the terminal's cursor should
    be left when nothing is being done with it.  This must
@@ -111,10 +114,17 @@ 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;
@@ -156,6 +166,7 @@ make_window ()
   XSETFASTINT (p->height, 0);
   XSETFASTINT (p->width, 0);
   XSETFASTINT (p->hscroll, 0);
+  XSETFASTINT (p->last_point, 0);
   XSETFASTINT (p->last_point_x, 0);
   XSETFASTINT (p->last_point_y, 0);
   p->start = Fmake_marker ();
@@ -449,7 +460,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;
@@ -557,13 +568,15 @@ have been if redisplay had finished, do this:\n\
       (vertical-motion (1- (window-height window)) window)\n\
       (point))")  */
 
-DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0,
+DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
   "Return position at which display currently ends in WINDOW.\n\
 This is updated by redisplay, when it runs to completion.\n\
 Simply changing the buffer text or setting `window-start'\n\
-does not update this value.")
-  (window)
-     Lisp_Object window;
+does not update this value.\n\
+If UP-TO-DATE is non-nil, compute the up-to-date position\n\
+if it isn't already recorded.")
+  (window, update)
+     Lisp_Object window, update;
 {
   Lisp_Object value;
   struct window *w = decode_window (window);
@@ -581,8 +594,20 @@ does not update this value.")
     return Qnil;
 #endif
 
-  XSETINT (value,
-          BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
+  if (! NILP (update)
+      && ! (! NILP (w->window_end_valid)
+           && XFASTINT (w->last_modified) >= MODIFF))
+    {
+      int opoint = PT, opoint_byte = PT_BYTE;
+      TEMP_SET_PT_BOTH (XMARKER (w->start)->charpos,
+                       XMARKER (w->start)->bytepos);
+      Fvertical_motion (make_number (window_internal_height (w)), Qnil);
+      XSETINT (value, PT);
+      TEMP_SET_PT_BOTH (opoint, opoint_byte);
+    }
+  else
+    XSETINT (value,
+            BUF_Z (XBUFFER (buf)) - XFASTINT (w->window_end_pos));
 
   return value;
 }
@@ -678,6 +703,9 @@ window_display_table (w)
   tem = w->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
+  if (NILP (w->buffer))
+    return 0;
+
   tem = XBUFFER (w->buffer)->display_table;
   if (DISP_TABLE_P (tem))
     return XCHAR_TABLE (tem);
@@ -702,18 +730,20 @@ DEFUN ("set-window-display-table", Fset_window_display_table, Sset_window_displa
 \f
 /* Record info on buffer window w is displaying
    when it is about to cease to display that buffer.  */
-static
+static void
 unshow_buffer (w)
      register struct window *w;
 {
   Lisp_Object buf;
+  struct buffer *b;
 
   buf = w->buffer;
-  if (XBUFFER (buf) != XMARKER (w->pointm)->buffer)
+  b = XBUFFER (buf);
+  if (b != XMARKER (w->pointm)->buffer)
     abort ();
 
-  if (w == XWINDOW (XBUFFER (buf)->last_selected_window))
-    XBUFFER (buf)->last_selected_window = Qnil;
+  if (w == XWINDOW (b->last_selected_window))
+    b->last_selected_window = Qnil;
 
 #if 0
   if (w == XWINDOW (selected_window)
@@ -728,20 +758,23 @@ unshow_buffer (w)
        selected window, while last_window_start reflects another
        window which was recently showing the same buffer.
        Some people might say that might be a good thing.  Let's see.  */
-    XBUFFER (buf)->last_window_start = marker_position (w->start);
+    b->last_window_start = marker_position (w->start);
 
   /* Point in the selected window's buffer
      is actually stored in that buffer, and the window's pointm isn't used.
      So don't clobber point in that buffer.  */
   if (! EQ (buf, XWINDOW (selected_window)->buffer))
-    BUF_PT (XBUFFER (buf))
-      = clip_to_bounds (BUF_BEGV (XBUFFER (buf)),
-                       marker_position (w->pointm),
-                       BUF_ZV (XBUFFER (buf)));
+    temp_set_point_both (b,
+                        clip_to_bounds (BUF_BEGV (b),
+                                        XMARKER (w->pointm)->charpos,
+                                        BUF_ZV (b)),
+                        clip_to_bounds (BUF_BEGV_BYTE (b),
+                                        marker_byte_position (w->pointm),
+                                        BUF_ZV_BYTE (b)));
 }
 
 /* Put replacement into the window structure in place of old. */
-static
+static void
 replace_window (old, replacement)
      Lisp_Object old, replacement;
 {
@@ -785,6 +818,19 @@ 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;
+}
+
+void
+delete_window (window)
+     register Lisp_Object window;
 {
   register Lisp_Object tem, parent, sib;
   register struct window *p;
@@ -803,7 +849,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))
@@ -910,8 +956,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
 
@@ -1397,7 +1441,8 @@ window_loop (type, obj, mini, frames)
                  if (NILP (XWINDOW (w)->parent))
                    {
                      Lisp_Object new_buffer;
-                     new_buffer = Fother_buffer (obj, Qnil);
+                     new_buffer = Fother_buffer (obj, Qnil,
+                                                 XWINDOW (w)->frame);
                      if (NILP (new_buffer))
                        new_buffer
                          = Fget_buffer_create (build_string ("*scratch*"));
@@ -1432,7 +1477,7 @@ window_loop (type, obj, mini, frames)
                /* Find another buffer to show in this window.  */
                Lisp_Object another_buffer;
                FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (w)));
-               another_buffer = Fother_buffer (obj, Qnil);
+               another_buffer = Fother_buffer (obj, Qnil, XWINDOW (w)->frame);
                if (NILP (another_buffer))
                  another_buffer
                    = Fget_buffer_create (build_string ("*scratch*"));
@@ -1580,9 +1625,9 @@ value is reasonable when this function is called.")
         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_BYTE (pos.bufpos - 1) == '\n') ? Qt
+      set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+      w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+                              || FETCH_BYTE (pos.bytepos - 1) == '\n') ? Qt
                              : Qnil);
       /* We need to do this, so that the window-scroll-functions
         get called.  */
@@ -1597,17 +1642,20 @@ DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
   1, 2, "bDelete windows on (buffer): ",
   "Delete all windows showing BUFFER.\n\
 Optional second argument FRAME controls which frames are affected.\n\
-If nil or omitted, delete all windows showing BUFFER in any frame.\n\
-If t, delete only windows showing BUFFER in the selected frame.\n\
-If `visible', delete all windows showing BUFFER in any visible frame.\n\
-If a frame, delete only windows showing BUFFER in that frame.")
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is nil, search all frames.\n\
+If FRAME is t, search only the selected frame.\n\
+If FRAME is a frame, search only that frame.")
   (buffer, frame)
      Lisp_Object buffer, frame;
 {
   /* FRAME uses t and nil to mean the opposite of what window_loop
      expects.  */
-  if (! FRAMEP (frame))
-    frame = NILP (frame) ? Qt : Qnil;
+  if (NILP (frame))
+    frame = Qt;
+  else if (EQ (frame, Qt))
+    frame = Qnil;
 
   if (!NILP (buffer))
     {
@@ -1648,9 +1696,9 @@ replace_buffer_in_all_windows (buffer)
      because it only considers frames on the current keyboard.
      So loop manually over frames, and handle each one.  */
   FOR_EACH_FRAME (tail, frame)
-    window_loop (UNSHOW_BUFFER, buffer, 0, frame);
+    window_loop (UNSHOW_BUFFER, buffer, 1, frame);
 #else
-  window_loop (UNSHOW_BUFFER, buffer, 0, Qt);
+  window_loop (UNSHOW_BUFFER, buffer, 1, Qt);
 #endif
 }
 \f
@@ -1702,6 +1750,7 @@ check_frame_size (frame, rows, cols)
    nodelete nonzero means do not do this.
    (The caller should check later and do so if appropriate)  */
 
+void
 set_window_height (window, height, nodelete)
      Lisp_Object window;
      int height;
@@ -1717,9 +1766,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;
     }
 
@@ -1770,6 +1821,7 @@ set_window_height (window, height, nodelete)
 
 /* Recursively set width of WINDOW and its inferiors. */
 
+void
 set_window_width (window, width, nodelete)
      Lisp_Object window;
      int width;
@@ -1783,7 +1835,7 @@ set_window_width (window, width, nodelete)
 
   if (!nodelete && width < window_min_width && !NILP (w->parent))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
@@ -1875,12 +1927,17 @@ BUFFER can be a buffer or buffer name.")
   if (EQ (window, selected_window))
     XBUFFER (w->buffer)->last_selected_window = window;
 
+  /* Update time stamps of buffer display.  */
+  if (INTEGERP (XBUFFER (buffer)->display_count))
+    XSETINT (XBUFFER (buffer)->display_count,
+            XINT (XBUFFER (buffer)->display_count) + 1);
+  XBUFFER (buffer)->display_time = Fcurrent_time ();
+
   XSETFASTINT (w->window_end_pos, 0);
   w->window_end_valid = Qnil;
   XSETFASTINT (w->hscroll, 0);
-  Fset_marker (w->pointm,
-              make_number (BUF_PT (XBUFFER (buffer))),
-              buffer);
+  set_marker_both (w->pointm, buffer,
+                  BUF_PT (XBUFFER (buffer)), BUF_PT_BYTE (XBUFFER (buffer)));
   set_marker_restricted (w->start,
                         make_number (XBUFFER (buffer)->last_window_start),
                         buffer);
@@ -1907,6 +1964,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;
@@ -1914,10 +1975,19 @@ BUFFER can be a buffer or buffer name.")
 
 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0,
   "Select WINDOW.  Most editing will apply to WINDOW's buffer.\n\
-The main editor command loop selects the buffer of the selected window\n\
-before each command.")
+If WINDOW is not already selected, also make WINDOW's buffer current.\n\
+Note that the main editor command loop\n\
+selects the buffer of the selected window before each command.")
   (window)
      register Lisp_Object window;
+{
+  return select_window_1 (window, 1);
+}
+\f
+static Lisp_Object
+select_window_1 (window, recordflag)
+     register Lisp_Object window;
+     int recordflag;
 {
   register struct window *w;
   register struct window *ow = XWINDOW (selected_window);
@@ -1933,8 +2003,10 @@ before each command.")
   if (EQ (window, selected_window))
     return window;
 
-  Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))),
-              ow->buffer);
+  if (! NILP (ow->buffer))
+    set_marker_both (ow->pointm, ow->buffer,
+                    BUF_PT (XBUFFER (ow->buffer)),
+                    BUF_PT_BYTE (XBUFFER (ow->buffer)));
 
   selected_window = window;
   if (XFRAME (WINDOW_FRAME (w)) != selected_frame)
@@ -1949,7 +2021,8 @@ before each command.")
   else
     selected_frame->selected_window = window;
 
-  record_buffer (w->buffer);
+  if (recordflag)
+    record_buffer (w->buffer);
   Fset_buffer (w->buffer);
 
   XBUFFER (w->buffer)->last_selected_window = window;
@@ -1972,7 +2045,7 @@ before each command.")
   windows_or_buffers_changed++;
   return window;
 }
-
+\f
 /* Deiconify the frame containing the window WINDOW,
    unless it is the selected frame;
    then return WINDOW.
@@ -2028,7 +2101,7 @@ See `special-display-buffer-names', and `special-display-regexps'.")
       else if (CONSP (car)
               && STRINGP (XCAR (car))
               && fast_string_match (XCAR (car), buffer_name) >= 0)
-       return XCDR (tem);
+       return XCDR (car);
     }
   return Qnil;
 }  
@@ -2065,8 +2138,9 @@ See `same-window-buffer-names' and `same-window-regexps'.")
   return Qnil;
 }
 
-DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2,
-       "bDisplay buffer: \nP",
+   /* Use B so the default is (other-buffer).  */
+DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 3,
+     "BDisplay buffer: \nP",
   "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\
@@ -2077,9 +2151,18 @@ Returns the window displaying BUFFER.\n\
 \n\
 The variables `special-display-buffer-names', `special-display-regexps',\n\
 `same-window-buffer-names', and `same-window-regexps' customize how certain\n\
-buffer names are handled.")
-  (buffer, not_this_window)
-     register Lisp_Object buffer, not_this_window;
+buffer names are handled.\n\
+\n\
+If optional argument FRAME is `visible', search all visible frames.\n\
+If FRAME is 0, search all visible and iconified frames.\n\
+If FRAME is t, search all frames.\n\
+If FRAME is a frame, search only that frame.\n\
+If FRAME is nil, search only the selected frame\n\
+ (actually the last nonminibuffer frame),\n\
+ unless `pop-up-frames' is non-nil,\n\
+ which means search visible and iconified frames.")
+  (buffer, not_this_window, frame)
+     register Lisp_Object buffer, not_this_window, frame;
 {
   register Lisp_Object window, tem;
 
@@ -2108,7 +2191,9 @@ buffer names are handled.")
   /* If pop_up_frames,
      look for a window showing BUFFER on any visible or iconified frame.
      Otherwise search only the current frame.  */
-  if (pop_up_frames || last_nonminibuf_frame == 0)
+  if (! NILP (frame))
+    tem = frame;
+  else if (pop_up_frames || last_nonminibuf_frame == 0)
     XSETFASTINT (tem, 0);
   else
     XSETFRAME (tem, last_nonminibuf_frame);
@@ -2195,13 +2280,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.  */
@@ -2216,15 +2308,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;
            }
        }
@@ -2244,6 +2340,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;
@@ -2256,17 +2354,18 @@ temp_output_buffer_show (buf)
     call1 (Vtemp_buffer_show_function, buf);
   else
     {
-      window = Fdisplay_buffer (buf, Qnil);
+      window = Fdisplay_buffer (buf, Qnil, Qnil);
 
       if (XFRAME (XWINDOW (window)->frame) != selected_frame)
        Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
       Vminibuf_scroll_window = window;
       w = XWINDOW (window);
       XSETFASTINT (w->hscroll, 0);
-      set_marker_restricted (w->start, make_number (1), buf);
-      set_marker_restricted (w->pointm, make_number (1), buf);
+      set_marker_restricted_both (w->start, buf, 1, 1);
+      set_marker_restricted_both (w->pointm, buf, 1, 1);
 
-      /* Run temp-buffer-show-hook, with the chosen window selected.  */
+      /* Run temp-buffer-show-hook, with the chosen window selected
+        and it sbuffer current.  */
       if (!NILP (Vrun_hooks))
        {
          Lisp_Object tem;
@@ -2277,13 +2376,17 @@ temp_output_buffer_show (buf)
              if (!NILP (tem))
                {
                  int count = specpdl_ptr - specpdl;
+                 Lisp_Object prev_window;
+                 prev_window = selected_window;
 
                  /* Select the window that was chosen, for running the hook.  */
                  record_unwind_protect (Fset_window_configuration,
                                         Fcurrent_window_configuration (Qnil));
 
-                 Fselect_window (window);
+                 select_window_1 (window, 0);
+                 Fset_buffer (w->buffer);
                  call1 (Vrun_hooks, Qtemp_buffer_show_hook);
+                 select_window_1 (prev_window, 0);
                  unbind_to (count, Qnil);
                }
            }
@@ -2291,7 +2394,7 @@ temp_output_buffer_show (buf)
     }
 }
 \f
-static
+static void
 make_dummy_parent (window)
      Lisp_Object window;
 {
@@ -2362,8 +2465,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 ();
 
@@ -2417,8 +2518,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))
@@ -2438,6 +2537,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
@@ -2449,6 +2550,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;
 }
 
@@ -2460,6 +2565,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;
 }
 
@@ -2494,6 +2603,7 @@ window_width (window)
    also changes the heights of the siblings so as to
    keep everything consistent. */
 
+void
 change_window_height (delta, widthflag)
      register int delta;
      int widthflag;
@@ -2502,10 +2612,10 @@ change_window_height (delta, widthflag)
   Lisp_Object window;
   register struct window *p;
   int *sizep;
-  int (*sizefun) () = widthflag ? window_width : window_height;
-  register int (*setsizefun) () = (widthflag
-                                  ? set_window_width
-                                  : set_window_height);
+  int (*sizefun) P_ ((Lisp_Object))
+    = widthflag ? window_width : window_height;
+  register void (*setsizefun) P_ ((Lisp_Object, int, int))
+    = (widthflag ? set_window_width : set_window_height);
   int maximum;
   Lisp_Object next, prev;
 
@@ -2549,7 +2659,7 @@ change_window_height (delta, widthflag)
 
   if (*sizep + delta < MINSIZE (window))
     {
-      Fdelete_window (window);
+      delete_window (window);
       return;
     }
 
@@ -2564,7 +2674,7 @@ change_window_height (delta, widthflag)
     maximum += (*sizefun) (prev) - MINSIZE (prev);
 
   /* If we can get it all from them, do so.  */
-  if (delta < maximum)
+  if (delta <= maximum)
     {
       Lisp_Object first_unaffected;
       Lisp_Object first_affected;
@@ -2715,7 +2825,8 @@ window_scroll (window, n, whole, noerror)
 {
   register struct window *w = XWINDOW (window);
   register int opoint = PT;
-  register int pos;
+  register int opoint_byte = PT_BYTE;
+  register int pos, pos_byte;
   register int ht = window_internal_height (w);
   register Lisp_Object tem;
   int lose;
@@ -2745,8 +2856,9 @@ window_scroll (window, n, whole, noerror)
   lose = n < 0 && PT == BEGV;
   Fvertical_motion (make_number (n), window);
   pos = PT;
+  pos_byte = PT_BYTE;
   bolp = Fbolp ();
-  SET_PT (opoint);
+  SET_PT_BOTH (opoint, opoint_byte);
 
   if (lose)
     {
@@ -2767,7 +2879,7 @@ window_scroll (window, n, whole, noerror)
       if (XINT (w->height) < 4 * scroll_margin)
        this_scroll_margin = XINT (w->height) / 4;
 
-      set_marker_restricted (w->start, make_number (pos), w->buffer);
+      set_marker_restricted_both (w->start, w->buffer, pos, pos_byte);
       w->start_at_line_beg = bolp;
       w->update_mode_line = Qt;
       XSETFASTINT (w->last_modified, 0);
@@ -2778,7 +2890,7 @@ window_scroll (window, n, whole, noerror)
 
       if (whole && scroll_preserve_screen_position)
        {
-         SET_PT (pos);
+         SET_PT_BOTH (pos, pos_byte);
          Fvertical_motion (make_number (original_vpos), window);
        }
       /* If we scrolled forward, put point enough lines down
@@ -2789,7 +2901,7 @@ window_scroll (window, n, whole, noerror)
 
          if (this_scroll_margin > 0)
            {
-             SET_PT (pos);
+             SET_PT_BOTH (pos, pos_byte);
              Fvertical_motion (make_number (this_scroll_margin), window);
              top_margin = PT;
            }
@@ -2797,14 +2909,14 @@ window_scroll (window, n, whole, noerror)
            top_margin = pos;
 
          if (top_margin <= opoint)
-           SET_PT (opoint);
+           SET_PT_BOTH (opoint, opoint_byte);
          else if (scroll_preserve_screen_position)
            {
-             SET_PT (pos);
+             SET_PT_BOTH (pos, pos_byte);
              Fvertical_motion (make_number (original_vpos), window);
            }
          else
-           SET_PT (pos);
+           SET_PT (top_margin);
        }
       else if (n < 0)
        {
@@ -2812,7 +2924,7 @@ window_scroll (window, n, whole, noerror)
 
          /* If we scrolled backward, put point near the end of the window
             but not within the scroll margin.  */
-         SET_PT (pos);
+         SET_PT_BOTH (pos, pos_byte);
          tem = Fvertical_motion (make_number (ht - this_scroll_margin), window);
          if (XFASTINT (tem) == ht - this_scroll_margin)
            bottom_margin = PT;
@@ -2820,12 +2932,12 @@ window_scroll (window, n, whole, noerror)
            bottom_margin = PT + 1;
 
          if (bottom_margin > opoint)
-           SET_PT (opoint);
+           SET_PT_BOTH (opoint, opoint_byte);
          else
            {
              if (scroll_preserve_screen_position)
                {
-                 SET_PT (pos);
+                 SET_PT_BOTH (pos, pos_byte);
                  Fvertical_motion (make_number (original_vpos), window);
                }
              else
@@ -2881,7 +2993,8 @@ DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P",
   "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2890,10 +3003,11 @@ When calling from a program, supply a number as argument or nil.")
 }
 
 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P",
-  "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\
+  "Scroll text of current window down ARG lines; or near full screen if no ARG.\n\
 A near full screen is `next-screen-context-lines' less than a full screen.\n\
 Negative ARG means scroll upward.\n\
-When calling from a program, supply a number as argument or nil.")
+If ARG is the atom `-', scroll upward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.")
   (arg)
      Lisp_Object arg;
 {
@@ -2919,7 +3033,7 @@ showing that buffer is used.")
     {
       window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil);
       if (NILP (window))
-       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt);
+       window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt, Qnil);
     }
   else
     {
@@ -2946,9 +3060,11 @@ showing that buffer is used.")
 
 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P",
   "Scroll next window upward ARG lines; or near full screen if no ARG.\n\
+A near full screen is `next-screen-context-lines' less than a full screen.\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.  Negative ARG means scroll downward.\n\
-When calling from a program, supply a number as argument or nil.\n\
+If ARG is the atom `-', scroll downward by nearly full screen.\n\
+When calling from a program, supply as argument a number, nil, or `-'.\n\
 \n\
 If in the minibuffer, `minibuffer-scroll-window' if non-nil\n\
 specifies the window to scroll.\n\
@@ -2986,7 +3102,7 @@ showing that buffer, popping the buffer up if necessary.")
       window_scroll (window, XINT (arg), 0, 1);
     }
 
-  Fset_marker (w->pointm, make_number (PT), Qnil);
+  set_marker_both (w->pointm, Qnil, PT, PT_BYTE);
   unbind_to (count, Qnil);
 
   return Qnil;
@@ -3039,6 +3155,8 @@ redraws with point in the center of the current window.")
   register struct window *w = XWINDOW (selected_window);
   register int ht = window_internal_height (w);
   struct position pos;
+  struct buffer *buf = XBUFFER (w->buffer);
+  struct buffer *obuf = current_buffer;
 
   if (NILP (arg))
     {
@@ -3060,13 +3178,15 @@ redraws with point in the center of the current window.")
   if (XINT (arg) < 0)
     XSETINT (arg, XINT (arg) + ht);
 
+  set_buffer_internal (buf);
   pos = *vmotion (PT, - XINT (arg), w);
 
-  Fset_marker (w->start, make_number (pos.bufpos), w->buffer);
-  w->start_at_line_beg = ((pos.bufpos == BEGV
-                          || FETCH_BYTE (pos.bufpos - 1) == '\n')
+  set_marker_both (w->start, w->buffer, pos.bufpos, pos.bytepos);
+  w->start_at_line_beg = ((pos.bytepos == BEGV_BYTE
+                          || FETCH_BYTE (pos.bytepos - 1) == '\n')
                          ? Qt : Qnil);
   w->force_start = Qt;
+  set_buffer_internal (obuf);
 
   return Qnil;
 }
@@ -3099,12 +3219,12 @@ negative means relative to bottom of window.")
   if (start < BEGV || start > ZV)
     {
       Fvertical_motion (make_number (- (height / 2)), window);
-      Fset_marker (w->start, make_number (PT), w->buffer);
+      set_marker_both (w->start, w->buffer, PT, PT_BYTE);
       w->start_at_line_beg = Fbolp ();
       w->force_start = Qt;
     }
   else
-    SET_PT (start);
+    Fgoto_char (w->start);
 
   return Fvertical_motion (arg, window);
 }
@@ -3123,11 +3243,12 @@ struct save_window_data
     /* 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, interpreted as a struct saved_window */
+    /* A vector, each of whose elements is a struct saved_window
+       for one window.  */
     Lisp_Object saved_windows;
   };
 
-/* This is saved as a Lisp_Vector */
+/* This is saved as a Lisp_Vector  */
 struct saved_window
   {
     /* these first two must agree with struct Lisp_Vector in lisp.h */
@@ -3147,7 +3268,7 @@ struct saved_window
   ((struct saved_window *) (XVECTOR ((swv)->contents[(n)])))
 
 DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0,
-  "T if OBJECT is a window-configuration object.")
+  "Return t if OBJECT is a window-configuration object.")
   (object)
      Lisp_Object object;
 {
@@ -3156,7 +3277,6 @@ DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_
   return Qnil;
 }
 
-
 DEFUN ("set-window-configuration", Fset_window_configuration,
   Sset_window_configuration, 1, 1, 0,
   "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\
@@ -3170,6 +3290,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))
     {
@@ -3183,6 +3304,12 @@ 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);
@@ -3203,15 +3330,29 @@ 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);
+       change_frame_size (f, XFASTINT (data->frame_height),
+                          XFASTINT (data->frame_width), 0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (XFASTINT (data->frame_menu_bar_lines)
          != previous_frame_menu_bar_lines)
-       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, data->frame_menu_bar_lines, make_number (0));
 #endif
 
+      if (! NILP (XWINDOW (selected_window)->buffer))
+       {
+         w = XWINDOW (selected_window);
+         set_marker_both (w->pointm,
+                          w->buffer,
+                          BUF_PT (XBUFFER (w->buffer)),
+                          BUF_PT_BYTE (XBUFFER (w->buffer)));
+       }
+
       windows_or_buffers_changed++;
       FRAME_WINDOW_SIZES_CHANGED (f) = 1;
 
@@ -3288,14 +3429,10 @@ by `current-window-configuration' (which see).")
                {
                  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);
+                 set_marker_restricted (w->start, p->start, w->buffer);
+                 set_marker_restricted (w->pointm, p->pointm, w->buffer);
                  Fset_marker (XBUFFER (w->buffer)->mark,
-                              Fmarker_position (p->mark), w->buffer);
+                              p->mark, w->buffer);
 
                  /* As documented in Fcurrent_window_configuration, don't
                     save the location of point in the buffer which was current
@@ -3323,10 +3460,9 @@ by `current-window-configuration' (which see).")
                    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);
+                   set_marker_restricted_both (w->pointm, w->buffer,
+                                               BUF_PT (XBUFFER (w->buffer)),
+                                               BUF_PT_BYTE (XBUFFER (w->buffer)));
                  w->start_at_line_beg = Qt;
                }
            }
@@ -3334,6 +3470,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)
@@ -3354,27 +3492,43 @@ by `current-window-configuration' (which see).")
                           0, 0);
 #if defined (HAVE_WINDOW_SYSTEM) || defined (MSDOS)
       if (previous_frame_menu_bar_lines != FRAME_MENU_BAR_LINES (f))
-       x_set_menu_bar_lines (f, previous_frame_menu_bar_lines, 0);
+       x_set_menu_bar_lines (f, make_number (previous_frame_menu_bar_lines),
+                             make_number (0));
 #endif
+
+      UNBLOCK_INPUT;
+
+      /* Fselect_window will have made f the selected frame, so we
+        reselect the proper frame here.  Fhandle_switch_frame will change the
+        selected window too, but that doesn't make the call to
+        Fselect_window above totally superfluous; it still sets f's
+        selected window.  */
+      if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
+       do_switch_frame (data->selected_frame, Qnil, 0);
+
+      if (! NILP (Vwindow_configuration_change_hook)
+         && ! NILP (Vrun_hooks))
+       call1 (Vrun_hooks, Qwindow_configuration_change_hook);
+    }
+
+  if (!NILP (new_current_buffer))
+    {
+      Fset_buffer (new_current_buffer);
+
+      /* 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);
     }
 
   /* Restore the minimum heights recorded in the configuration.  */
   window_min_height = XINT (data->min_height);
   window_min_width = XINT (data->min_width);
 
-  /* Fselect_window will have made f the selected frame, so we
-     reselect the proper frame here.  Fhandle_switch_frame will change the
-     selected window too, but that doesn't make the call to
-     Fselect_window above totally superfluous; it still sets f's
-     selected window.  */
-  if (FRAME_LIVE_P (XFRAME (data->selected_frame)))
-    do_switch_frame (data->selected_frame, Qnil, 0);
-
-  if (!NILP (new_current_buffer))
-    Fset_buffer (new_current_buffer);
-
   Vminibuf_scroll_window = data->minibuf_scroll_window;
-  return (Qnil);
+
+  return Qnil;
 }
 
 /* Mark all windows now on frame as deleted
@@ -3451,8 +3605,9 @@ save_window_save (window, vector, i)
          if (EQ (window, selected_window))
            {
              p->pointm = Fmake_marker ();
-             Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)),
-                          w->buffer);
+             set_marker_both (p->pointm, w->buffer,
+                              BUF_PT (XBUFFER (w->buffer)),
+                              BUF_PT_BYTE (XBUFFER (w->buffer)));
            }
          else
            p->pointm = Fcopy_marker (w->pointm, Qnil);
@@ -3567,6 +3722,119 @@ Does not restore the value of point in current buffer.")
   return unbind_to (count, val);
 }
 \f
+/* Return 1 if window configurations C1 and C2
+   describe the same state of affairs.  This is used by Fequal.   */
+
+int
+compare_window_configurations (c1, c2, ignore_positions)
+     Lisp_Object c1, c2;
+     int ignore_positions;
+{
+  register struct save_window_data *d1, *d2;
+  struct Lisp_Vector *sw1, *sw2;
+  int i;
+
+  d1 = (struct save_window_data *) XVECTOR (c1);
+  d2 = (struct save_window_data *) XVECTOR (c2);
+  sw1 = XVECTOR (d1->saved_windows);
+  sw2 = XVECTOR (d2->saved_windows);
+
+  if (! EQ (d1->frame_width, d2->frame_width))
+    return 0;
+  if (! EQ (d1->frame_height, d2->frame_height))
+    return 0;
+  if (! EQ (d1->frame_menu_bar_lines, d2->frame_menu_bar_lines))
+    return 0;
+  if (! EQ (d1->selected_frame, d2->selected_frame))
+    return 0;
+  /* Don't compare the current_window field directly.
+     Instead see w1_is_current and w2_is_current, below.  */
+  if (! EQ (d1->current_buffer, d2->current_buffer))
+    return 0;
+  if (! ignore_positions)
+    if (! EQ (d1->minibuf_scroll_window, d2->minibuf_scroll_window))
+      return 0;
+  /* Don't compare the root_window field.
+     We don't require the two configurations
+     to use the same window object,
+     and the two root windows must be equivalent
+     if everything else compares equal.  */
+  if (! EQ (d1->focus_frame, d2->focus_frame))
+    return 0;
+  if (! EQ (d1->min_width, d2->min_width))
+    return 0;
+  if (! EQ (d1->min_height, d2->min_height))
+    return 0;
+
+  /* Verify that the two confis have the same number of windows.  */
+  if (sw1->size != sw2->size)
+    return 0;
+
+  for (i = 0; i < sw1->size; i++)
+    {
+      struct saved_window *p1, *p2;
+      int w1_is_current, w2_is_current;
+
+      p1 = SAVED_WINDOW_N (sw1, i);
+      p2 = SAVED_WINDOW_N (sw2, i);
+
+      /* Verify that the current windows in the two
+        configurations correspond to each other.  */
+      w1_is_current = EQ (d1->current_window, p1->window);
+      w2_is_current = EQ (d2->current_window, p2->window);
+
+      if (w1_is_current != w2_is_current)
+       return 0;
+
+      /* Verify that the corresponding windows do match.  */
+      if (! EQ (p1->buffer, p2->buffer))
+       return 0;
+      if (! EQ (p1->left, p2->left))
+       return 0;
+      if (! EQ (p1->top, p2->top))
+       return 0;
+      if (! EQ (p1->width, p2->width))
+       return 0;
+      if (! EQ (p1->height, p2->height))
+       return 0;
+      if (! EQ (p1->display_table, p2->display_table))
+       return 0;
+      if (! EQ (p1->parent, p2->parent))
+       return 0;
+      if (! EQ (p1->prev, p2->prev))
+       return 0;
+      if (! ignore_positions)
+       {
+         if (! EQ (p1->hscroll, p2->hscroll))
+           return 0;
+         if (! EQ (p1->start_at_line_beg, p2->start_at_line_beg))
+           return 0;
+         if (NILP (Fequal (p1->start, p2->start)))
+           return 0;
+         if (NILP (Fequal (p1->pointm, p2->pointm)))
+           return 0;
+         if (NILP (Fequal (p1->mark, p2->mark)))
+           return 0;
+       }
+    }
+
+  return 1;
+}
+
+DEFUN ("compare-window-configurations", Fcompare_window_configurations,
+       Scompare_window_configurations, 2, 2, 0,
+  "Compare two window configurations as regards the structure of windows.\n\
+This function ignores details such as the values of point and mark\n\
+and scrolling positions.")
+  (x, y)
+     Lisp_Object x, y;
+{
+  if (compare_window_configurations (x, y, 1))
+    return Qt;
+  return Qnil;
+}
+\f
+void
 init_window_once ()
 {
   selected_frame = make_terminal_frame ();
@@ -3578,8 +3846,13 @@ init_window_once ()
   window_initialized = 1;
 }
 
+void
 syms_of_window ()
 {
+  staticpro (&Qwindow_configuration_change_hook);
+  Qwindow_configuration_change_hook
+    = intern ("window-configuration-change-hook");
+
   Qwindowp = intern ("windowp");
   staticpro (&Qwindowp);
 
@@ -3636,7 +3909,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,
@@ -3651,7 +3929,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,
@@ -3719,6 +4002,12 @@ If there is only one window, it is split regardless of this value.");
     "*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 frame is the one whose configuration has changed.");
+  Vwindow_configuration_change_hook = Qnil;
+
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);
@@ -3774,8 +4063,10 @@ If there is only one window, it is split regardless of this value.");
   defsubr (&Sset_window_configuration);
   defsubr (&Scurrent_window_configuration);
   defsubr (&Ssave_window_excursion);
+  defsubr (&Scompare_window_configurations);
 }
 
+void
 keys_of_window ()
 {
   initial_define_key (control_x_map, '1', "delete-other-windows");