XEmacs 21.2.36 "Notos"
[chise/xemacs-chise.git.1] / src / window.c
index 26193ca..cfa89b4 100644 (file)
@@ -36,10 +36,12 @@ Boston, MA 02111-1307, USA.  */
 #include "glyphs.h"
 #include "redisplay.h"
 #include "window.h"
+#include "elhash.h"
 #include "commands.h"
+#include "gutter.h"
 
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configurationp;
-Lisp_Object Qscroll_up, Qscroll_down, Qdisplay_buffer;
+Lisp_Object Qdisplay_buffer;
 
 #ifdef MEMORY_USAGE_STATS
 Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
@@ -80,9 +82,12 @@ Lisp_Object Vvertical_divider_shadow_thickness;
 /* Divider surface width (not counting 3-d borders) */
 Lisp_Object Vvertical_divider_line_width;
 
-/* Spacing between outer egde of divider border and window edge */
+/* Spacing between outer edge of divider border and window edge */
 Lisp_Object Vvertical_divider_spacing;
 
+/* How much to scroll by per-line. */
+Lisp_Object Vwindow_pixel_scroll_increment;
+
 /* Scroll if point lands on the bottom line and that line is partially
    clipped. */
 int scroll_on_clipped_lines;
@@ -116,7 +121,7 @@ Lisp_Object Qtemp_buffer_show_hook;
 int next_screen_context_lines;
 
 /* List of freed window configurations with 1 - 10 windows. */
-Lisp_Object Vwindow_configuration_free_list[10];
+static Lisp_Object Vwindow_configuration_free_list[10];
 
 #define SET_LAST_MODIFIED(w, cache_too)                \
 do {                                           \
@@ -136,36 +141,38 @@ do {                                              \
 
 \f
 #define MARK_DISP_VARIABLE(field)              \
-  ((markobj) (window->field[CURRENT_DISP]));   \
-  ((markobj) (window->field[DESIRED_DISP]));   \
-  ((markobj) (window->field[CMOTION_DISP]));
+  mark_object (window->field[CURRENT_DISP]);   \
+  mark_object (window->field[DESIRED_DISP]);   \
+  mark_object (window->field[CMOTION_DISP]);
 
 static Lisp_Object
-mark_window (Lisp_Object obj, void (*markobj) (Lisp_Object))
+mark_window (Lisp_Object obj)
 {
   struct window *window = XWINDOW (obj);
-  ((markobj) (window->frame));
-  ((markobj) (window->mini_p));
-  ((markobj) (window->next));
-  ((markobj) (window->prev));
-  ((markobj) (window->hchild));
-  ((markobj) (window->vchild));
-  ((markobj) (window->parent));
-  ((markobj) (window->buffer));
+  mark_object (window->frame);
+  mark_object (window->mini_p);
+  mark_object (window->next);
+  mark_object (window->prev);
+  mark_object (window->hchild);
+  mark_object (window->vchild);
+  mark_object (window->parent);
+  mark_object (window->buffer);
   MARK_DISP_VARIABLE (start);
   MARK_DISP_VARIABLE (pointm);
-  ((markobj) (window->sb_point));      /* #### move to scrollbar.c? */
-  ((markobj) (window->use_time));
+  mark_object (window->sb_point);      /* #### move to scrollbar.c? */
+  mark_object (window->use_time);
   MARK_DISP_VARIABLE (last_modified);
   MARK_DISP_VARIABLE (last_point);
   MARK_DISP_VARIABLE (last_start);
   MARK_DISP_VARIABLE (last_facechange);
-  ((markobj) (window->line_cache_last_updated));
-  ((markobj) (window->redisplay_end_trigger));
-  mark_face_cachels (window->face_cachels, markobj);
-  mark_glyph_cachels (window->glyph_cachels, markobj);
+  mark_object (window->line_cache_last_updated);
+  mark_object (window->redisplay_end_trigger);
+  mark_object (window->subwindow_instance_cache);
+
+  mark_face_cachels (window->face_cachels);
+  mark_glyph_cachels (window->glyph_cachels);
 
-#define WINDOW_SLOT(slot, compare) ((markobj) (window->slot))
+#define WINDOW_SLOT(slot, compare) mark_object (window->slot)
 #include "winslots.h"
 
   return Qnil;
@@ -228,7 +235,7 @@ finalize_window (void *header, int for_disksave)
 
 DEFINE_LRECORD_IMPLEMENTATION ("window", window,
                                mark_window, print_window, finalize_window,
-                              0, 0, struct window);
+                              0, 0, 0, struct window);
 
 
 #define INIT_DISP_VARIABLE(field, initialization)      \
@@ -249,7 +256,7 @@ Lisp_Object
 allocate_window (void)
 {
   Lisp_Object val;
-  struct window *p = alloc_lcrecord_type (struct window, lrecord_window);
+  struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
 
   zero_lcrecord (p);
   XSETWINDOW (val, p);
@@ -274,12 +281,20 @@ allocate_window (void)
   p->face_cachels     = Dynarr_new (face_cachel);
   p->glyph_cachels    = Dynarr_new (glyph_cachel);
   p->line_start_cache = Dynarr_new (line_start_cache);
+  p->subwindow_instance_cache = make_lisp_hash_table (30,
+                                                     HASH_TABLE_KEY_VALUE_WEAK,
+                                                     HASH_TABLE_EQ);
   p->line_cache_last_updated = Qzero;
   INIT_DISP_VARIABLE (last_point_x, 0);
   INIT_DISP_VARIABLE (last_point_y, 0);
   INIT_DISP_VARIABLE (window_end_pos, 0);
   p->redisplay_end_trigger = Qnil;
 
+  p->gutter_extent_modiff[0] = 0;
+  p->gutter_extent_modiff[1] = 0;
+  p->gutter_extent_modiff[2] = 0;
+  p->gutter_extent_modiff[3] = 0;
+
 #define WINDOW_SLOT(slot, compare) p->slot = Qnil
 #include "winslots.h"
 
@@ -385,23 +400,21 @@ static Lisp_Object
 real_window_internal (Lisp_Object win, struct window_mirror *rmir,
                      struct window_mirror *mir)
 {
-  Lisp_Object retval;
-
   for (; !NILP (win) && rmir ; win = XWINDOW (win)->next, rmir = rmir->next)
     {
       if (mir == rmir)
        return win;
       if (!NILP (XWINDOW (win)->vchild))
        {
-         retval = real_window_internal (XWINDOW (win)->vchild, rmir->vchild,
-                                        mir);
+         Lisp_Object retval =
+           real_window_internal (XWINDOW (win)->vchild, rmir->vchild, mir);
          if (!NILP (retval))
            return retval;
        }
       if (!NILP (XWINDOW (win)->hchild))
        {
-         retval = real_window_internal (XWINDOW (win)->hchild, rmir->hchild,
-                                        mir);
+         Lisp_Object retval =
+           real_window_internal (XWINDOW (win)->hchild, rmir->hchild, mir);
          if (!NILP (retval))
            return retval;
        }
@@ -637,7 +650,7 @@ window_full_width_p (struct window *w)
   return window_is_leftmost (w) && window_is_rightmost (w);
 }
 
-static int
+int
 window_is_highest (struct window *w)
 {
   Lisp_Object parent, current_ancestor, window;
@@ -665,7 +678,7 @@ window_is_highest (struct window *w)
     return 0;
 }
 
-static int
+int
 window_is_lowest (struct window *w)
 {
   Lisp_Object parent, current_ancestor, window;
@@ -701,6 +714,11 @@ window_full_height_p (struct window *w)
 int
 window_truncation_on (struct window *w)
 {
+    /* Minibuffer windows are never truncated.
+       #### is this the right way ? */
+  if (MINI_WINDOW_P (w))
+    return 0;
+
   /* Horizontally scrolled windows are truncated. */
   if (w->hscroll)
     return 1;
@@ -719,6 +737,17 @@ window_truncation_on (struct window *w)
   return 0;
 }
 
+DEFUN ("window-truncated-p", Fwindow_truncated_p, 0, 1, 0, /*
+Returns non-nil if text in the window is truncated.
+*/
+       (window))
+{
+  struct window *w = decode_window (window);
+
+  return window_truncation_on (w) ? Qt : Qnil;
+}
+
+
 static int
 have_undivided_common_edge (struct window *w_right, void *closure)
 {
@@ -746,7 +775,7 @@ window_needs_vertical_divider_1 (struct window *w)
     return 1;
 
 #ifdef HAVE_SCROLLBARS
-  /* Our right scrollabr is enough to separate us at the right */
+  /* Our right scrollbar is enough to separate us at the right */
   if (NILP (w->scrollbar_on_left_p)
       && !NILP (w->vertical_scrollbar_visible_p)
       && !ZEROP (w->scrollbar_width))
@@ -785,7 +814,7 @@ invalidate_vertical_divider_cache_in_window (struct window *w,
 /* Calculate width of vertical divider, including its shadows
    and spacing. The returned value is effectively the distance
    between adjacent window edges. This function does not check
-   whether a windows needs vertival divider, so the returned 
+   whether a window needs a vertical divider, so the returned
    value is a "theoretical" one */
 int
 window_divider_width (struct window *w)
@@ -794,7 +823,7 @@ window_divider_width (struct window *w)
      will have a depressed look */
 
   if (FRAME_WIN_P (XFRAME (WINDOW_FRAME (w))))
-    return 
+    return
       XINT (w->vertical_divider_line_width)
       + 2 * XINT (w->vertical_divider_spacing)
       + 2 * abs (XINT (w->vertical_divider_shadow_thickness));
@@ -893,7 +922,7 @@ window_modeline_height (struct window *w)
                /* This should be an abort except I'm not yet 100%
                    confident that it won't ever get hit (though I
                    haven't been able to trigger it).  It is extremely
-                   unlikely to cause any noticable problem and even if
+                   unlikely to cause any noticeable problem and even if
                    it does it will be a minor display glitch. */
                /* #### Bullshit alert.  It does get hit and it causes
                    noticeable glitches.  real_current_modeline_height
@@ -968,32 +997,6 @@ window_right_margin_width (struct window *w)
   return margin_width_internal (w, 0);
 }
 
-static int
-window_top_toolbar_height (struct window *w)
-{
-  /* #### implement this shit. */
-  return 0;
-}
-
-/* #### Currently used in scrollbar.c.  Does it actually need to be? */
-int
-window_bottom_toolbar_height (struct window *w)
-{
-  return 0;
-}
-
-static int
-window_left_toolbar_width (struct window *w)
-{
-  return 0;
-}
-
-static int
-window_right_toolbar_width (struct window *w)
-{
-  return 0;
-}
-
 /*****************************************************************************
  Window Gutters
 
@@ -1012,63 +1015,75 @@ window_right_toolbar_width (struct window *w)
  relative to the frame, not the window.
  ****************************************************************************/
 
-int
-window_top_gutter_height (struct window *w)
+static int
+window_top_window_gutter_height (struct window *w)
 {
-  int toolbar_height = window_top_toolbar_height (w);
-
   if (!NILP (w->hchild) || !NILP (w->vchild))
     return 0;
 
 #ifdef HAVE_SCROLLBARS
   if (!NILP (w->scrollbar_on_top_p))
-    return window_scrollbar_height (w) + toolbar_height;
+    return window_scrollbar_height (w);
   else
 #endif
-    return toolbar_height;
+    return 0;
 }
 
 int
-window_bottom_gutter_height (struct window *w)
+window_top_gutter_height (struct window *w)
+{
+  return window_top_window_gutter_height (w);
+}
+
+static int
+window_bottom_window_gutter_height (struct window *w)
 {
-  int other_height;
+  int gutter;
 
   if (!NILP (w->hchild) || !NILP (w->vchild))
     return 0;
-  else
-    other_height =
-      window_modeline_height (w) + window_bottom_toolbar_height (w);
+
+  gutter = window_modeline_height (w);
 
 #ifdef HAVE_SCROLLBARS
   if (NILP (w->scrollbar_on_top_p))
-    return window_scrollbar_height (w) + other_height;
+    return window_scrollbar_height (w) + gutter;
   else
 #endif
-    return other_height;
+    return gutter;
 }
 
 int
-window_left_gutter_width (struct window *w, int modeline)
+window_bottom_gutter_height (struct window *w)
+{
+  return window_bottom_window_gutter_height (w);
+}
+
+static int
+window_left_window_gutter_width (struct window *w, int modeline)
 {
-  int gutter = window_left_toolbar_width (w);
-  
   if (!NILP (w->hchild) || !NILP (w->vchild))
     return 0;
 
-
 #ifdef HAVE_SCROLLBARS
   if (!modeline && !NILP (w->scrollbar_on_left_p))
-    gutter += window_scrollbar_width (w);
+    return window_scrollbar_width (w);
 #endif
 
-  return gutter;
+  return 0;
 }
 
 int
-window_right_gutter_width (struct window *w, int modeline)
+window_left_gutter_width (struct window *w, int modeline)
+{
+  return window_left_window_gutter_width (w, modeline);
+}
+
+static int
+window_right_window_gutter_width (struct window *w, int modeline)
 {
-  int gutter = window_left_toolbar_width (w);
-  
+  int gutter = 0;
+
   if (!NILP (w->hchild) || !NILP (w->vchild))
     return 0;
 
@@ -1083,6 +1098,18 @@ window_right_gutter_width (struct window *w, int modeline)
   return gutter;
 }
 
+int
+window_right_gutter_width (struct window *w, int modeline)
+{
+  return window_right_window_gutter_width (w, modeline);
+}
+
+static int
+window_pixel_height (struct window* w)
+{
+  return WINDOW_HEIGHT (w);
+}
+
 \f
 DEFUN ("windowp", Fwindowp, 1, 1, 0, /*
 Return t if OBJ is a window.
@@ -1119,6 +1146,26 @@ be used.  Otherwise, the selected frame is used.
   }
 }
 
+DEFUN ("last-nonminibuf-window", Flast_nonminibuf_window, 0, 1, 0, /*
+Return the last selected window that is not a minibuffer window.
+If the optional argument CON-DEV-OR-FRAME is specified and is a frame,
+return the last non-minibuffer window used by that frame.  If
+CON-DEV-OR-FRAME is a device, then the selected frame on that device
+will be used.  If CON-DEV-OR-FRAME is a console, the selected frame on
+that console's selected device will be used.  Otherwise, the selected
+frame is used.
+*/
+       (con_dev_or_frame))
+{
+  if (NILP (con_dev_or_frame) && NILP (Fselected_device (Qnil)))
+    return Qnil; /* happens at startup */
+
+  {
+    struct frame *f = decode_frame_or_selected (con_dev_or_frame);
+    return FRAME_LAST_NONMINIBUF_WINDOW (f);
+  }
+}
+
 DEFUN ("minibuffer-window", Fminibuffer_window, 0, 1, 0, /*
 Return the window used now for minibuffers.
 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
@@ -1132,7 +1179,7 @@ be used.  Otherwise, the selected frame is used.
   return FRAME_MINIBUF_WINDOW (decode_frame_or_selected (con_dev_or_frame));
 }
 
-DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, 1, 1, 0, /*
+DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, 0, 1, 0, /*
 Return non-nil if WINDOW is a minibuffer window.
 */
        (window))
@@ -1278,6 +1325,22 @@ be different.
 Use `window-height' to get consistent results in geometry calculations.
 Use `window-displayed-height' to get the actual number of lines
 currently displayed in a window.
+
+The names are somewhat confusing; here's a table to help out:
+
+                    width                         height
+-------------------------------------------------------------------------
+w/o gutters
+  (rows/columns)    window-width                  window-text-area-height
+  (pixels)          window-text-area-pixel-width  window-text-area-pixel-height
+
+with gutters
+  (rows/columns)    window-full-width             window-height
+  (pixels)          window-pixel-width            window-pixel-height
+
+actually displayed
+  (rows/columns)    ----                          window-displayed-height
+  (pixels)          ----                     window-displayed-text-pixel-height
 */
        (window))
 {
@@ -1304,7 +1367,20 @@ This includes the window's modeline and horizontal scrollbar (if any).
 */
        (window))
 {
-  return make_int (decode_window (window)->pixel_height);
+  return make_int (window_pixel_height (decode_window (window)));
+}
+
+DEFUN ("window-text-area-height", Fwindow_text_area_height, 0, 1, 0, /*
+Return the number of default lines in the text area of WINDOW.
+This actually works by dividing the window's text area pixel height (i.e.
+excluding the modeline and horizontal scrollbar, if any) by the height of the
+default font; therefore, the number of displayed lines will probably
+be different.
+See also `window-height' and `window-displayed-height'.
+*/
+       (window))
+{
+  return make_int (window_char_height (decode_window (window), 0));
 }
 
 DEFUN ("window-text-area-pixel-height",
@@ -1341,7 +1417,7 @@ is non-nil, do not include space occupied by clipped lines.
   if (NILP (window))
     window = Fselected_window (Qnil);
 
-  CHECK_WINDOW (window);
+  CHECK_LIVE_WINDOW (window);
   w = XWINDOW (window);
 
   start  = marker_position (w->start[CURRENT_DISP]);
@@ -1385,13 +1461,25 @@ is non-nil, do not include space occupied by clipped lines.
 
 DEFUN ("window-width", Fwindow_width, 0, 1, 0, /*
 Return the number of display columns in WINDOW.
-This is the width that is usable columns available for text in WINDOW.
+This is the width that is usable columns available for text in WINDOW,
+and does not include vertical scrollbars, dividers, or the like.  See also
+`window-full-width' and `window-height'.
 */
        (window))
 {
   return make_int (window_char_width (decode_window (window), 0));
 }
 
+DEFUN ("window-full-width", Fwindow_full_width, 0, 1, 0, /*
+Return the total number of columns in WINDOW.
+This is like `window-width' but includes vertical scrollbars, dividers,
+etc.
+*/
+       (window))
+{
+  return make_int (window_char_width (decode_window (window), 1));
+}
+
 DEFUN ("window-pixel-width", Fwindow_pixel_width, 0, 1, 0, /*
 Return the width of WINDOW in pixels.  Defaults to current window.
 */
@@ -1404,7 +1492,7 @@ DEFUN ("window-text-area-pixel-width",
        Fwindow_text_area_pixel_width, 0, 1, 0, /*
 Return the width in pixels of the text-displaying portion of WINDOW.
 Unlike `window-pixel-width', the space occupied by the vertical
-scrollbar or divider, if any, is not counted.  
+scrollbar or divider, if any, is not counted.
 */
      (window))
 {
@@ -1421,22 +1509,23 @@ Return the number of columns by which WINDOW is scrolled from left margin.
   return make_int (decode_window (window)->hscroll);
 }
 
-#ifdef MODELINE_IS_SCROLLABLE
 DEFUN ("modeline-hscroll", Fmodeline_hscroll, 0, 1, 0, /*
-Return the number of columns by which WINDOW's modeline is scrolled from
-left margin. If the window has no modeline, return nil.
+Return the horizontal scrolling amount of WINDOW's modeline.
+If the window has no modeline, return nil.
 */
        (window))
 {
   struct window *w = decode_window (window);
 
-  return (WINDOW_HAS_MODELINE_P (w)) ? make_int (w->modeline_hscroll) : Qnil;
+  return (WINDOW_HAS_MODELINE_P (w)) ? make_int ((int) w->modeline_hscroll) :
+    Qnil;
 }
 
 DEFUN ("set-modeline-hscroll", Fset_modeline_hscroll, 2, 2, 0, /*
-Set number of columns WINDOW's modeline is scrolled from left margin to NCOL.
-NCOL should be zero or positive. If NCOL is negative, it will be forced to 0.
-If the window has no modeline, do nothing and return nil.
+Set the horizontal scrolling amount of WINDOW's modeline to NCOL.
+If NCOL is negative, it will silently be forced to 0.
+If the window has no modeline, return nil. Otherwise, return the actual
+value that was set.
 */
        (window, ncol))
 {
@@ -1444,18 +1533,20 @@ If the window has no modeline, do nothing and return nil.
 
   if (WINDOW_HAS_MODELINE_P (w))
     {
-      int ncols;
+      Charcount ncols;
+
       CHECK_INT (ncol);
-      ncols = XINT (ncol);
-      if (ncols < 0) ncols = 0;
-      if (w->modeline_hscroll != ncols)
-       MARK_MODELINE_CHANGED;
-      w->modeline_hscroll = ncols;
-      return ncol;
+      ncols = (XINT (ncol) <= 0) ? 0 : (Charcount) XINT (ncol);
+      if (ncols != w->modeline_hscroll)
+       {
+         MARK_MODELINE_CHANGED;
+         w->modeline_hscroll = ncols;
+       }
+      return make_int ((int) ncols);
     }
+
   return Qnil;
 }
-#endif /* MODELINE_IS_SCROLLABLE */
 
 DEFUN ("set-window-hscroll", Fset_window_hscroll, 2, 2, 0, /*
 Set number of columns WINDOW is scrolled from left margin to NCOL.
@@ -1507,15 +1598,17 @@ Afterwards the end-trigger value is reset to nil.
 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, 0, 1, 0, /*
 Return a list of the pixel edge coordinates of WINDOW.
 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
-The frame toolbars and menubars are considered to be outside of this area.
+The frame toolbars, menubars and gutters are considered to be outside of this area.
 */
        (window))
 {
   struct window *w = decode_window (window);
   struct frame *f = XFRAME (w->frame);
 
-  int left = w->pixel_left - FRAME_LEFT_BORDER_END (f);
-  int top  = w->pixel_top  - FRAME_TOP_BORDER_END  (f);
+  int left =
+    w->pixel_left - FRAME_LEFT_BORDER_END (f) - FRAME_LEFT_GUTTER_BOUNDS (f);
+  int top =
+    w->pixel_top - FRAME_TOP_BORDER_END (f) - FRAME_TOP_GUTTER_BOUNDS (f);
 
   return list4 (make_int (left),
                make_int (top),
@@ -1546,7 +1639,7 @@ top left corner of the window.
 
 DEFUN ("window-point", Fwindow_point, 0, 1, 0, /*
 Return current value of point in WINDOW.
-For a nonselected window, this is the value point would have
+For a non-selected window, this is the value point would have
 if that window were selected.
 
 Note that, when WINDOW is the selected window and its buffer
@@ -1604,6 +1697,28 @@ slower with this flag set.
     }
 }
 
+DEFUN ("window-last-line-visible-height", Fwindow_last_line_visible_height, 0, 1, 0, /*
+Return pixel height of visible part of last window line if it is clipped.
+If the last line is not clipped, return nil.
+*/
+       (window))
+{
+  struct window *w = decode_window (window);
+  display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
+  int num_lines = Dynarr_length (dla);
+  struct display_line *dl;
+
+  /* No lines - no clipped lines */
+  if (num_lines == 0 || (num_lines == 1 && Dynarr_atp (dla, 0)->modeline))
+    return Qnil;
+
+  dl = Dynarr_atp (dla, num_lines - 1);
+  if (dl->clip == 0)
+    return Qnil;
+
+  return make_int (dl->ascent + dl->descent - dl->clip);
+}
+
 DEFUN ("set-window-point", Fset_window_point, 2, 2, 0, /*
 Make point value in WINDOW be at position POS in WINDOW's buffer.
 */
@@ -1755,6 +1870,16 @@ replace_window (Lisp_Object old, Lisp_Object replacement)
   /* #### Here, if replacement is a vertical combination
      and so is its new parent, we should make replacement's
      children be children of that parent instead. */
+
+  ERROR_CHECK_SUBWINDOW_CACHE (p);
+}
+
+static void
+window_unmap_subwindows (struct window* w)
+{
+  assert (!NILP (w->subwindow_instance_cache));
+  elisp_maphash (unmap_subwindow_instance_cache_mapper,
+                w->subwindow_instance_cache, (void*)1);
 }
 
 /* we're deleting W; set the structure of W to indicate this. */
@@ -1762,6 +1887,20 @@ replace_window (Lisp_Object old, Lisp_Object replacement)
 static void
 mark_window_as_deleted (struct window *w)
 {
+  /* The window instance cache is going away now, so need to get the
+     cachels reset by redisplay. */
+  MARK_FRAME_SUBWINDOWS_CHANGED (XFRAME (WINDOW_FRAME (w)));
+
+  /* The cache is going away. If we leave unmapping to
+     reset_subwindow_cachels then we get in a situation where the
+     domain (the window) has been deleted but we still need access to
+     its attributes in order to unmap windows properly. Since the
+     subwindows are going to get GC'd anyway as a result of the domain
+     going away, it is safer to just unmap them all while we know the
+     domain is still valid. */
+  ERROR_CHECK_SUBWINDOW_CACHE (w);
+  window_unmap_subwindows (w);
+
   /* In the loop
      (while t (split-window) (delete-window))
      we end up with a tree of deleted windows which are all connected
@@ -1773,13 +1912,13 @@ mark_window_as_deleted (struct window *w)
      Since the window-configuration code doesn't need any of the
      pointers to other windows (they are all recreated from the
      window-config data), we set them all to nil so that we
-     are able to collect more actual garbage.
-   */
+     are able to collect more actual garbage. */
   w->next = Qnil;
   w->prev = Qnil;
   w->hchild = Qnil;
   w->vchild = Qnil;
   w->parent = Qnil;
+  w->subwindow_instance_cache = Qnil;
 
   w->dead = 1;
 
@@ -1816,6 +1955,7 @@ will automatically call `save-buffers-kill-emacs'.)
     window = Fselected_window (Qnil);
   else
     CHECK_WINDOW (window);
+
   w = XWINDOW (window);
 
   /* It's okay to delete an already-deleted window.  */
@@ -1849,6 +1989,12 @@ will automatically call `save-buffers-kill-emacs'.)
   par = XWINDOW (parent);
 
   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
+  /* It's quite likely that deleting a window will result in
+     subwindows needing to be deleted also (since they are cached
+     per-window). So we mark them as changed, so that the cachels will
+     get reset by redisplay and thus deleted subwindows can get
+     GC'd. */
+  MARK_FRAME_SUBWINDOWS_CHANGED (f);
 
   /* Are we trying to delete any frame's selected window?
      Note that we could be dealing with a non-leaf window
@@ -1964,7 +2110,7 @@ will automatically call `save-buffers-kill-emacs'.)
 
 \f
 DEFUN ("next-window", Fnext_window, 0, 4, 0, /*
-Return next window after WINDOW in canonical ordering of windows.
+Return the next window after WINDOW in the canonical ordering of windows.
 If omitted, WINDOW defaults to the selected window.
 
 Optional second arg MINIBUF t means count the minibuffer window even
@@ -1985,7 +2131,7 @@ ALL-FRAMES = 0 means include windows on all visible and iconified frames.
 If ALL-FRAMES is a frame, restrict search to windows on that frame.
 Anything else means restrict to WINDOW's frame.
 
-Optional fourth argument CONSOLE controls which consoles or devices the
+Optional fourth arg CONSOLE controls which consoles or devices the
 returned window may be on.  If CONSOLE is a console, return windows only
 on that console.  If CONSOLE is a device, return windows only on that
 device.  If CONSOLE is a console type, return windows only on consoles
@@ -2016,8 +2162,9 @@ windows, eventually ending up back at the window you started with.
     minibuf = (minibuf_level ? minibuf_window : Qlambda);
   else if (! EQ (minibuf, Qt))
     minibuf = Qlambda;
-  /* Now minibuf can be t => count all minibuffer windows,
-     lambda => count none of them,
+  /* Now `minibuf' is one of:
+     t      => count all minibuffer windows
+     lambda => count none of them
      or a specific minibuffer window (the active one) to count.  */
 
   /* all_frames == nil doesn't specify which frames to include.  */
@@ -2038,11 +2185,12 @@ windows, eventually ending up back at the window you started with.
     return frame_first_window (XFRAME (all_frames));
   else if (! EQ (all_frames, Qt))
     all_frames = Qnil;
-  /* Now all_frames is t meaning search all frames,
-     nil meaning search just current frame,
-     visible meaning search just visible frames,
-     0 meaning search visible and iconified frames,
-     or a window, meaning search the frame that window belongs to.  */
+  /* Now `all_frames' is one of:
+     t        => search all frames
+     nil      => search just the current frame
+     visible  => search just visible frames
+     0        => search visible and iconified frames
+     a window => search the frame that window belongs to.  */
 
   /* Do this loop at least once, to get the next window, and perhaps
      again, if we hit the minibuffer and that is not acceptable.  */
@@ -2061,10 +2209,9 @@ windows, eventually ending up back at the window you started with.
 
            if (! NILP (all_frames))
              {
-               Lisp_Object tem1;
-
-               tem1 = tem;
+               Lisp_Object tem1 = tem;
                tem = next_frame (tem, all_frames, console);
+
                /* In the case where the minibuffer is active,
                   and we include its frame as well as the selected one,
                   next_frame may get stuck in that frame.
@@ -2091,7 +2238,6 @@ windows, eventually ending up back at the window you started with.
          else break;
        }
     }
-  /* "acceptable" is the correct spelling. */
   /* Which windows are acceptable?
      Exit the loop and accept this window if
      this isn't a minibuffer window,
@@ -2107,7 +2253,7 @@ windows, eventually ending up back at the window you started with.
 }
 
 DEFUN ("previous-window", Fprevious_window, 0, 4, 0, /*
-Return the window preceding WINDOW in canonical ordering of windows.
+Return the window preceding WINDOW in the canonical ordering of windows.
 If omitted, WINDOW defaults to the selected window.
 
 Optional second arg MINIBUF t means count the minibuffer window even
@@ -2119,16 +2265,16 @@ Several frames may share a single minibuffer; if the minibuffer
 counts, all windows on all frames that share that minibuffer count
 too.  Therefore, `previous-window' can be used to iterate through
 the set of windows even when the minibuffer is on another frame.  If
-the minibuffer does not count, only windows from WINDOW's frame count
+the minibuffer does not count, only windows from WINDOW's frame count.
 
-If optional third arg ALL-FRAMES t means include windows on all frames.
+Optional third arg ALL-FRAMES t means include windows on all frames.
 ALL-FRAMES nil or omitted means cycle within the frames as specified
 above.  ALL-FRAMES = `visible' means include windows on all visible frames.
 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
 If ALL-FRAMES is a frame, restrict search to windows on that frame.
 Anything else means restrict to WINDOW's frame.
 
-Optional fourth argument CONSOLE controls which consoles or devices the
+Optional fourth arg CONSOLE controls which consoles or devices the
 returned window may be on.  If CONSOLE is a console, return windows only
 on that console.  If CONSOLE is a device, return windows only on that
 device.  If CONSOLE is a console type, return windows only on consoles
@@ -2159,8 +2305,9 @@ windows, eventually ending up back at the window you started with.
     minibuf = (minibuf_level ? minibuf_window : Qlambda);
   else if (! EQ (minibuf, Qt))
     minibuf = Qlambda;
-  /* Now minibuf can be t => count all minibuffer windows,
-     lambda => count none of them,
+  /* Now `minibuf' is one of:
+     t      => count all minibuffer windows
+     lambda => count none of them
      or a specific minibuffer window (the active one) to count.  */
 
   /* all_frames == nil doesn't specify which frames to include.
@@ -2182,11 +2329,12 @@ windows, eventually ending up back at the window you started with.
     return frame_first_window (XFRAME (all_frames));
   else if (! EQ (all_frames, Qt))
     all_frames = Qnil;
-  /* Now all_frames is t meaning search all frames,
-     nil meaning search just current frame,
-     visible meaning search just visible frames,
-     0 meaning search visible and iconified frames,
-     or a window, meaning search the frame that window belongs to.  */
+  /* Now `all_frames' is one of:
+     t        => search all frames
+     nil      => search just the current frame
+     visible  => search just visible frames
+     0        => search visible and iconified frames
+     a window => search the frame that window belongs to.  */
 
   /* Do this loop at least once, to get the next window, and perhaps
      again, if we hit the minibuffer and that is not acceptable.  */
@@ -2204,7 +2352,7 @@ windows, eventually ending up back at the window you started with.
            tem = WINDOW_FRAME (XWINDOW (window));
 
            if (! NILP (all_frames))
-             /* It's actually important that we use prev_frame here,
+             /* It's actually important that we use previous_frame here,
                 rather than next_frame.  All the windows acceptable
                 according to the given parameters should form a ring;
                 Fnext_window and Fprevious_window should go back and
@@ -2214,10 +2362,8 @@ windows, eventually ending up back at the window you started with.
                 window_loop assumes that these `ring' requirement are
                 met.  */
              {
-               Lisp_Object tem1;
-
-               tem1 = tem;
-               tem = prev_frame (tem, all_frames, console);
+               Lisp_Object tem1 = tem;
+               tem = previous_frame (tem, all_frames, console);
                /* In the case where the minibuffer is active,
                   and we include its frame as well as the selected one,
                   next_frame may get stuck in that frame.
@@ -2403,20 +2549,19 @@ window_loop (enum window_loop type,
   int lose_lose = 0;
   Lisp_Object devcons, concons;
 
-  /* FRAME_ARG is Qlambda to stick to one frame,
-     Qvisible to consider all visible frames,
-     or Qt otherwise.  */
-
   /* If we're only looping through windows on a particular frame,
      FRAME points to that frame.  If we're looping through windows
      on all frames, FRAME is 0.  */
-
   if (FRAMEP (frames))
     frame = XFRAME (frames);
   else if (NILP (frames))
     frame = selected_frame ();
   else
     frame = 0;
+
+  /* FRAME_ARG is Qlambda to stick to one frame,
+     Qvisible to consider all visible frames,
+     or Qt otherwise.  */
   if (frame)
     frame_arg = Qlambda;
   else if (ZEROP (frames))
@@ -2437,7 +2582,10 @@ window_loop (enum window_loop type,
       if (NILP (the_frame))
        continue;
 
-      if (!device_matches_console_spec (the_frame, device, console))
+      if (!device_matches_console_spec (device,
+                                       NILP (console) ?
+                                       FRAME_CONSOLE (XFRAME (the_frame)) :
+                                       console))
        continue;
 
       /* Pick a window to start with.  */
@@ -2463,7 +2611,7 @@ window_loop (enum window_loop type,
 
          /* Pick the next window now, since some operations will delete
             the current window.  */
-         next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, Qt);
+         next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, device);
 
          /* #### Still needed ?? */
          /* Given the outstanding quality of the rest of this code,
@@ -2580,7 +2728,7 @@ window_loop (enum window_loop type,
                            new_buffer = Fother_buffer (obj, Qnil, Qnil);
                            if (NILP (new_buffer))
                              new_buffer = Fget_buffer_create (QSscratch);
-                           Fset_window_buffer (w, new_buffer);
+                           Fset_window_buffer (w, new_buffer, Qnil);
                            if (EQ (w, Fselected_window (Qnil)))
                              Fset_buffer (p->buffer);
                          }
@@ -2652,7 +2800,7 @@ window_loop (enum window_loop type,
                          /* Otherwise show a different buffer in the
                              window.  */
                          p->dedicated = Qnil;
-                         Fset_window_buffer (w, another_buffer);
+                         Fset_window_buffer (w, another_buffer, Qnil);
                          if (EQ (w, Fselected_window (Qnil)))
                            Fset_buffer (p->buffer);
                        }
@@ -2953,17 +3101,41 @@ check_min_window_sizes (void)
     window_min_height = MIN_SAFE_WINDOW_HEIGHT;
 }
 
+static int
+frame_min_height (struct frame *frame)
+{
+  /* For height, we have to see whether the frame has a minibuffer, and
+     whether it wants a modeline.  */
+  return (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
+         : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
+         : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
+}
+
+/* Return non-zero if both frame sizes are less than or equal to
+   minimal allowed values. ROWS and COLS are in characters */
+int
+frame_size_valid_p (struct frame *frame, int rows, int cols)
+{
+  return (rows >= frame_min_height (frame)
+         && cols >= MIN_SAFE_WINDOW_WIDTH);
+}
+
+/* Return non-zero if both frame sizes are less than or equal to
+   minimal allowed values. WIDTH and HEIGHT are in pixels */
+int
+frame_pixsize_valid_p (struct frame *frame, int width, int height)
+{
+  int rows, cols;
+  pixel_to_real_char_size (frame, width, height, &cols, &rows);
+  return frame_size_valid_p (frame, rows, cols);
+}
+
 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
    minimum allowable size.  */
 void
 check_frame_size (struct frame *frame, int *rows, int *cols)
 {
-  /* For height, we have to see whether the frame has a minibuffer, and
-     whether it wants a modeline.  */
-  int min_height =
-    (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
-     : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
-     : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
+  int min_height = frame_min_height (frame);
 
   if (*rows < min_height)
     *rows = min_height;
@@ -3113,11 +3285,14 @@ set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete)
 \f
 static int window_select_count;
 
-DEFUN ("set-window-buffer", Fset_window_buffer, 2, 2, 0, /*
+DEFUN ("set-window-buffer", Fset_window_buffer, 2, 3, 0, /*
 Make WINDOW display BUFFER as its contents.
 BUFFER can be a buffer or buffer name.
+
+With non-nil optional argument NORECORD, do not modify the
+global or per-frame buffer ordering.
 */
-       (window, buffer))
+       (window, buffer, norecord))
 {
   Lisp_Object tem;
   struct window *w = decode_window (window);
@@ -3168,7 +3343,7 @@ BUFFER can be a buffer or buffer name.
   Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
   /* set start_at_line_beg correctly. GE */
   w->start_at_line_beg = beginning_of_line_p (XBUFFER (buffer),
-                                             marker_position (w->start[CURRENT_DISP]));  
+                                             marker_position (w->start[CURRENT_DISP]));
   w->force_start = 0;           /* Lucid fix */
   SET_LAST_MODIFIED (w, 1);
   SET_LAST_FACECHANGE (w);
@@ -3176,6 +3351,9 @@ BUFFER can be a buffer or buffer name.
   recompute_all_cached_specifiers_in_window (w);
   if (EQ (window, Fselected_window (Qnil)))
     {
+      if (NILP (norecord))
+       Frecord_buffer (buffer);
+
       Fset_buffer (buffer);
     }
   return Qnil;
@@ -3186,7 +3364,7 @@ Select WINDOW.  Most editing will apply to WINDOW's buffer.
 The main editor command loop selects the buffer of the selected window
 before each command.
 
-With non-nil optional argument `norecord', do not modify the
+With non-nil optional argument NORECORD, do not modify the
 global or per-frame buffer ordering.
 */
        (window, norecord))
@@ -3202,6 +3380,7 @@ global or per-frame buffer ordering.
     error ("Trying to select non-leaf window");
 
   w->use_time = make_int (++window_select_count);
+
   if (EQ (window, old_selected_window))
     return window;
 
@@ -3315,7 +3494,7 @@ make_dummy_parent (Lisp_Object window)
 {
   Lisp_Object new;
   struct window *o = XWINDOW (window);
-  struct window *p = alloc_lcrecord_type (struct window, lrecord_window);
+  struct window *p = alloc_lcrecord_type (struct window, &lrecord_window);
 
   XSETWINDOW (new, p);
   copy_lcrecord (p, o);
@@ -3325,6 +3504,10 @@ make_dummy_parent (Lisp_Object window)
   p->line_start_cache = Dynarr_new (line_start_cache);
   p->face_cachels     = Dynarr_new (face_cachel);
   p->glyph_cachels    = Dynarr_new (glyph_cachel);
+  p->subwindow_instance_cache =
+    make_lisp_hash_table (30,
+                         HASH_TABLE_KEY_VALUE_WEAK,
+                         HASH_TABLE_EQ);
 
   /* Put new into window structure in place of window */
   replace_window (window, new);
@@ -3348,7 +3531,7 @@ make_dummy_parent (Lisp_Object window)
 DEFUN ("split-window", Fsplit_window, 0, 3, "", /*
 Split WINDOW, putting SIZE lines in the first of the pair.
 WINDOW defaults to selected one and SIZE to half its size.
-If optional third arg HOR-FLAG is non-nil, split side by side
+If optional third arg HORFLAG is non-nil, split side by side
 and put SIZE columns in the first of the pair.
 */
        (window, chsize, horflag))
@@ -3362,7 +3545,7 @@ and put SIZE columns in the first of the pair.
   if (NILP (window))
     window = Fselected_window (Qnil);
   else
-    CHECK_WINDOW (window);
+    CHECK_LIVE_WINDOW (window);
 
   o = XWINDOW (window);
   f = XFRAME (WINDOW_FRAME (o));
@@ -3478,15 +3661,15 @@ and put SIZE columns in the first of the pair.
   /* do this last (after the window is completely initialized and
      the mirror-dirty flag is set) so that specifier recomputation
      caused as a result of this will work properly and not abort. */
-  Fset_window_buffer (new, o->buffer);
+  Fset_window_buffer (new, o->buffer, Qt);
   return new;
 }
 \f
 
 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /*
-Make the selected window ARG lines bigger.
-From program, optional second arg non-nil means grow sideways ARG columns,
-and optional third ARG specifies the window to change instead of the
+Make the selected window N lines bigger.
+From program, optional second arg SIDE non-nil means grow sideways N columns,
+and optional third arg WINDOW specifies the window to change instead of the
 selected window.
 */
        (n, side, window))
@@ -3498,9 +3681,9 @@ selected window.
 }
 
 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /*
-Make the selected window ARG pixels bigger.
-From program, optional second arg non-nil means grow sideways ARG pixels,
-and optional third ARG specifies the window to change instead of the
+Make the selected window N pixels bigger.
+From program, optional second arg SIDE non-nil means grow sideways N pixels,
+and optional third arg WINDOW specifies the window to change instead of the
 selected window.
 */
        (n, side, window))
@@ -3512,9 +3695,9 @@ selected window.
 }
 
 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /*
-Make the selected window ARG lines smaller.
-From program, optional second arg non-nil means shrink sideways ARG columns,
-and optional third ARG specifies the window to change instead of the
+Make the selected window N lines smaller.
+From program, optional second arg SIDE non-nil means shrink sideways N columns,
+and optional third arg WINDOW specifies the window to change instead of the
 selected window.
 */
        (n, side, window))
@@ -3526,9 +3709,9 @@ selected window.
 }
 
 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /*
-Make the selected window ARG pixels smaller.
-From program, optional second arg non-nil means shrink sideways ARG pixels,
-and optional third ARG specifies the window to change instead of the
+Make the selected window N pixels smaller.
+From program, optional second arg SIDE non-nil means shrink sideways N pixels,
+and optional third arg WINDOW specifies the window to change instead of the
 selected window.
 */
        (n, side, window))
@@ -3540,12 +3723,6 @@ selected window.
 }
 
 static int
-window_pixel_height (Lisp_Object window)
-{
-  return WINDOW_HEIGHT (XWINDOW (window));
-}
-
-static int
 window_pixel_height_to_char_height (struct window *w, int pixel_height,
                                    int include_gutters_p)
 {
@@ -3558,8 +3735,8 @@ window_pixel_height_to_char_height (struct window *w, int pixel_height,
 
   avail_height = (pixel_height -
                  (include_gutters_p ? 0 :
-                  window_top_gutter_height (w) +
-                  window_bottom_gutter_height (w)));
+                  window_top_window_gutter_height (w) +
+                  window_bottom_window_gutter_height (w)));
 
   default_face_height_and_width (window, &defheight, &defwidth);
 
@@ -3590,8 +3767,8 @@ window_char_height_to_pixel_height (struct window *w, int char_height,
   avail_height = char_height * defheight;
   pixel_height = (avail_height +
                  (include_gutters_p ? 0 :
-                  window_top_gutter_height (w) +
-                  window_bottom_gutter_height (w)));
+                  window_top_window_gutter_height (w) +
+                  window_bottom_window_gutter_height (w)));
 
   /* It's the calling function's responsibility to check these values
      and make sure they're not out of range.
@@ -3604,11 +3781,12 @@ window_char_height_to_pixel_height (struct window *w, int char_height,
 /* Return number of default lines of text can fit in the window W.
    If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
    horizontal scrollbar) in the space that is used for the calculation.
+   This doesn't include space used by the frame gutters.
    */
 int
 window_char_height (struct window *w, int include_gutters_p)
 {
-  return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
+  return window_pixel_height_to_char_height (w, window_pixel_height (w),
                                             include_gutters_p);
 }
 
@@ -3688,6 +3866,8 @@ window_pixel_width (Lisp_Object window)
   return WINDOW_WIDTH (XWINDOW (window));
 }
 
+/* Calculate the pixel of a window, optionally including margin space
+   but no vertical gutters. */
 static int
 window_pixel_width_to_char_width (struct window *w, int pixel_width,
                                  int include_margins_p)
@@ -3732,8 +3912,8 @@ window_char_width_to_pixel_width (struct window *w, int char_width,
 
   avail_width = char_width * defwidth;
   pixel_width = (avail_width +
-                window_left_gutter_width (w, 0) +
-                window_right_gutter_width (w, 0) +
+                window_left_window_gutter_width (w, 0) +
+                window_right_window_gutter_width (w, 0) +
                 (include_margins_p ? 0 : window_left_margin_width (w)) +
                 (include_margins_p ? 0 : window_right_margin_width (w)));
 
@@ -3772,6 +3952,12 @@ window_char_width (struct window *w, int include_margins_p)
   (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
    ? 1 : window_min_height)
 
+static int
+window_pixheight (Lisp_Object w)
+{
+  return window_pixel_height (XWINDOW (w));
+}
+
 /* Unlike set_window_pixheight, this function
    also changes the heights of the siblings so as to
    keep everything consistent. */
@@ -3787,7 +3973,7 @@ change_window_height (struct window *win, int delta, int widthflag,
   int *sizep;
   int (*sizefun) (Lisp_Object) = (widthflag
                                  ? window_pixel_width
-                                 : window_pixel_height);
+                                 : window_pixheight);
   void (*setsizefun) (Lisp_Object, int, int) = (widthflag
                                                ? set_window_pixwidth
                                                : set_window_pixheight);
@@ -3912,7 +4098,7 @@ change_window_height (struct window *win, int delta, int widthflag,
       (*setsizefun) (window, *sizep + delta1, 0);
 
       /* Squeeze out delta1 lines or columns from our parent,
-        shriking this window and siblings proportionately.
+        shrinking this window and siblings proportionately.
         This brings parent back to correct size.
         Delta1 was calculated so this makes this window the desired size,
         taking it all out of the siblings.  */
@@ -3922,6 +4108,8 @@ change_window_height (struct window *win, int delta, int widthflag,
   SET_LAST_MODIFIED (w, 0);
   SET_LAST_FACECHANGE (w);
   MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
+  /* overkill maybe, but better to be correct */
+  MARK_FRAME_GUTTERS_CHANGED (f);
 }
 #undef MINSIZE
 #undef CURBEG
@@ -3931,7 +4119,8 @@ change_window_height (struct window *win, int delta, int widthflag,
 
 \f
 
-/* Scroll contents of window WINDOW up N lines.  */
+/* Scroll contents of window WINDOW up N lines. If N < (top line height /
+   average line height) then we just adjust the top clip.  */
 void
 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
               Error_behavior errb)
@@ -3941,6 +4130,9 @@ window_scroll (Lisp_Object window, Lisp_Object n, int direction,
   int selected = EQ (window, Fselected_window (Qnil));
   int value = 0;
   Lisp_Object point, tem;
+  display_line_dynarr *dla;
+  int fheight, fwidth, modeline = 0;
+  struct display_line* dl;
 
   if (selected)
     point = make_int (BUF_PT (b));
@@ -3957,7 +4149,7 @@ window_scroll (Lisp_Object window, Lisp_Object n, int direction,
     }
 
   /* Always set force_start so that redisplay_window will run
-     thw window-scroll-functions.  */
+     the window-scroll-functions.  */
   w->force_start = 1;
 
   /* #### When the fuck does this happen?  I'm so glad that history has
@@ -3970,6 +4162,7 @@ window_scroll (Lisp_Object window, Lisp_Object n, int direction,
                         window, Qnil);
       Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
       w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
+      WINDOW_TEXT_TOP_CLIP (w) = 0;
       MARK_WINDOWS_CHANGED (w);
     }
 
@@ -4013,82 +4206,164 @@ window_scroll (Lisp_Object window, Lisp_Object n, int direction,
     {
       return;
     }
-  else if (value > 0)
-    {
-      int vtarget;
-      Bufpos startp, old_start;
 
-      old_start = marker_position (w->start[CURRENT_DISP]);
-      startp = vmotion (w, old_start, value, &vtarget);
+  /* Determine parameters to test for partial line scrolling with. */
+  dla = window_display_lines (w, CURRENT_DISP);
 
-      if (vtarget < value &&
-         (w->window_end_pos[CURRENT_DISP] == -1
-          || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
+  if (INTP (Vwindow_pixel_scroll_increment))
+    fheight = XINT (Vwindow_pixel_scroll_increment);
+  else if (!NILP (Vwindow_pixel_scroll_increment))
+    default_face_height_and_width (window, &fheight, &fwidth);
+
+  if (Dynarr_length (dla) >= 1)
+    modeline = Dynarr_atp (dla, 0)->modeline;
+
+  dl = Dynarr_atp (dla, modeline);
+
+  if (value > 0)
+    {
+      /* Go for partial display line scrolling. This just means bumping
+        the clip by a reasonable amount and redisplaying, everything else
+        remains unchanged. */
+      if (!NILP (Vwindow_pixel_scroll_increment)
+         &&
+         Dynarr_length (dla) >= (1 + modeline)
+         &&
+         (dl->ascent - dl->top_clip) - fheight * value > 0)
        {
-         maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
-         return;
+         WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
+         MARK_WINDOWS_CHANGED (w);
        }
       else
        {
-         set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
-                                w->buffer);
-         w->force_start = 1;
-         w->start_at_line_beg = beginning_of_line_p (b, startp);
-         MARK_WINDOWS_CHANGED (w);
+         int vtarget;
+         Bufpos startp, old_start;
 
-         if (!point_would_be_visible (w, startp, XINT (point)))
+         if (WINDOW_TEXT_TOP_CLIP (w))
            {
-             if (selected)
-               BUF_SET_PT (b, startp);
-             else
-               set_marker_restricted (w->pointm[CURRENT_DISP],
-                                      make_int (startp),
-                                      w->buffer);
+             WINDOW_TEXT_TOP_CLIP (w) = 0;
+             MARK_WINDOWS_CHANGED (w);
+           }
+
+         old_start = marker_position (w->start[CURRENT_DISP]);
+         startp = vmotion (w, old_start, value, &vtarget);
+
+         if (vtarget < value &&
+             (w->window_end_pos[CURRENT_DISP] == -1
+              || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
+           {
+             maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
+             return;
+           }
+         else
+           {
+             set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
+                                    w->buffer);
+             w->force_start = 1;
+             w->start_at_line_beg = beginning_of_line_p (b, startp);
+             MARK_WINDOWS_CHANGED (w);
+
+             if (!point_would_be_visible (w, startp, XINT (point)))
+               {
+                 if (selected)
+                   BUF_SET_PT (b, startp);
+                 else
+                   set_marker_restricted (w->pointm[CURRENT_DISP],
+                                          make_int (startp),
+                                          w->buffer);
+               }
            }
        }
     }
   else if (value < 0)
     {
-      int vtarget;
-      Bufpos startp, old_start;
-
-      old_start = marker_position (w->start[CURRENT_DISP]);
-      startp = vmotion (w, old_start, value, &vtarget);
-
-      if (vtarget > value
-         && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
+      /* Go for partial display line scrolling. This just means bumping
+        the clip by a reasonable amount and redisplaying, everything else
+        remains unchanged. */
+      if (!NILP (Vwindow_pixel_scroll_increment)
+         &&
+         Dynarr_length (dla) >= (1 + modeline)
+         &&
+         (dl->ascent - dl->top_clip) - fheight * value <
+         (dl->ascent + dl->descent - dl->clip)
+         &&
+         WINDOW_TEXT_TOP_CLIP (w) + value * fheight > 0)
        {
-         maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
-         return;
+         WINDOW_TEXT_TOP_CLIP (w) += value * fheight;
+         MARK_WINDOWS_CHANGED (w);
        }
       else
        {
-         set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
-                                w->buffer);
-         w->force_start = 1;
-         w->start_at_line_beg = beginning_of_line_p (b, startp);
-         MARK_WINDOWS_CHANGED (w);
+         int vtarget;
+         Bufpos startp, old_start;
 
-         if (!point_would_be_visible (w, startp, XINT (point)))
+         if (WINDOW_TEXT_TOP_CLIP (w))
            {
-             Bufpos new_point;
+             WINDOW_TEXT_TOP_CLIP (w) = 0;
+             MARK_WINDOWS_CHANGED (w);
+           }
 
-             if (MINI_WINDOW_P (w))
-               new_point = startp;
-             else
-               new_point = start_of_last_line (w, startp);
+         old_start = marker_position (w->start[CURRENT_DISP]);
+         startp = vmotion (w, old_start, value, &vtarget);
 
-             if (selected)
-               BUF_SET_PT (b, new_point);
-             else
-               set_marker_restricted (w->pointm[CURRENT_DISP],
-                                      make_int (new_point),
-                                      w->buffer);
+         if (vtarget > value
+             && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
+           {
+             maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
+             return;
+           }
+         else
+           {
+             set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
+                                    w->buffer);
+             w->force_start = 1;
+             w->start_at_line_beg = beginning_of_line_p (b, startp);
+             MARK_WINDOWS_CHANGED (w);
+
+             /* #### Scroll back by less than a line. This code was
+                originally for scrolling over large pixmaps and it
+                loses when a line being *exposed* at the top of the
+                window is bigger than the current one. However, for
+                pixel based scrolling in general we can guess that
+                the line we are going to display is probably the same
+                size as the one we are on. In that instance we can
+                have a reasonable stab at a suitable top clip. Fixing
+                this properly is hard (and probably slow) as we would
+                have to call redisplay to figure out the exposed line
+                size. */
+             if (!NILP (Vwindow_pixel_scroll_increment)
+                 && Dynarr_length (dla) >= (1 + modeline)
+                 && dl->ascent + fheight * value > 0)
+               {
+                 WINDOW_TEXT_TOP_CLIP (w) = (dl->ascent + fheight * value);
+               }
+
+             if (!point_would_be_visible (w, startp, XINT (point)))
+               {
+                 Bufpos new_point;
+
+                 if (MINI_WINDOW_P (w))
+                   new_point = startp;
+                 else
+                   new_point = start_of_last_line (w, startp);
+
+                 if (selected)
+                   BUF_SET_PT (b, new_point);
+                 else
+                   set_marker_restricted (w->pointm[CURRENT_DISP],
+                                          make_int (new_point),
+                                          w->buffer);
+               }
            }
        }
     }
   else /* value == 0 && direction == -1 */
     {
+      if (WINDOW_TEXT_TOP_CLIP (w))
+       {
+         WINDOW_TEXT_TOP_CLIP (w) = 0;
+         MARK_WINDOWS_CHANGED (w);
+       }
       if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
        {
          maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
@@ -4126,14 +4401,13 @@ window_scroll (Lisp_Object window, Lisp_Object n, int direction,
            }
        }
     }
-
 }
 \f
 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /*
-Scroll text of current window upward ARG lines; or near full screen if no ARG.
+Scroll text of current window upward N lines; or near full screen if no arg.
 A near full screen is `next-screen-context-lines' less than a full screen.
-Negative ARG means scroll downward.
-When calling from a program, supply a number as argument or nil.
+Negative N means scroll downward.
+When calling from a program, supply an integer as argument or nil.
 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
 signaled.
@@ -4145,9 +4419,9 @@ signaled.
 }
 
 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /*
-Scroll text of current window downward ARG lines; or near full screen if no ARG.
+Scroll text of current window downward N lines; or near full screen if no arg.
 A near full screen is `next-screen-context-lines' less than a full screen.
-Negative ARG means scroll upward.
+Negative N means scroll upward.
 When calling from a program, supply a number as argument or nil.
 On attempt to scroll past end of buffer, `end-of-buffer' is signaled.
 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is
@@ -4205,9 +4479,9 @@ showing that buffer is used.
  }
 
 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /*
-Scroll next window upward ARG lines; or near full frame if no ARG.
+Scroll next window upward N lines; or near full frame if no arg.
 The next window is the one below the current one; or the one at the top
-if the current one is at the bottom.  Negative ARG means scroll downward.
+if the current one is at the bottom.  Negative N means scroll downward.
 When calling from a program, supply a number as argument or nil.
 
 If in the minibuffer, `minibuffer-scroll-window' if non-nil
@@ -4222,37 +4496,33 @@ showing that buffer, popping the buffer up if necessary.
 }
 \f
 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /*
-Scroll selected window display ARG columns left.
-Default for ARG is window width minus 2.
+Scroll selected window display N columns left.
+Default for N is window width minus 2.
 */
-       (arg))
+       (n))
 {
   Lisp_Object window = Fselected_window (Qnil);
   struct window *w = XWINDOW (window);
+  int count = (NILP (n) ?
+              window_char_width (w, 0) - 2 :
+              XINT (Fprefix_numeric_value (n)));
 
-  if (NILP (arg))
-    arg = make_int (window_char_width (w, 0) - 2);
-  else
-    arg = Fprefix_numeric_value (arg);
-
-  return Fset_window_hscroll (window, make_int (w->hscroll + XINT (arg)));
+  return Fset_window_hscroll (window, make_int (w->hscroll + count));
 }
 
 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /*
-Scroll selected window display ARG columns right.
-Default for ARG is window width minus 2.
+Scroll selected window display N columns right.
+Default for N is window width minus 2.
 */
-       (arg))
+       (n))
 {
   Lisp_Object window = Fselected_window (Qnil);
   struct window *w = XWINDOW (window);
+  int count = (NILP (n) ?
+              window_char_width (w, 0) - 2 :
+              XINT (Fprefix_numeric_value (n)));
 
-  if (NILP (arg))
-    arg = make_int (window_char_width (w, 0) - 2);
-  else
-    arg = Fprefix_numeric_value (arg);
-
-  return Fset_window_hscroll (window, make_int (w->hscroll - XINT (arg)));
+  return Fset_window_hscroll (window, make_int (w->hscroll - count));
 }
 \f
 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /*
@@ -4304,7 +4574,7 @@ If WINDOW is nil, the selected window is used.
   if (NILP (window))
     window = Fselected_window (Qnil);
   else
-    CHECK_WINDOW (window);
+    CHECK_LIVE_WINDOW (window);
   w = XWINDOW (window);
   b = XBUFFER (w->buffer);
 
@@ -4431,7 +4701,7 @@ map_windows_1 (Lisp_Object window,
    non-zero, the mapping is halted.  Otherwise, map_windows() maps
    over all windows in F.
 
-   If MAPFUN creates or deletes windows, the behaviour is undefined.  */
+   If MAPFUN creates or deletes windows, the behavior is undefined.  */
 
 int
 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
@@ -4447,7 +4717,7 @@ map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
        {
          int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))),
                                 mapfun, closure);
-         if (v)     
+         if (v)
            return v;
        }
     }
@@ -4465,8 +4735,8 @@ modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
 }
 
 static void
-vertical_divider_changed_in_window (Lisp_Object specifier, 
-                                   struct window *w, 
+vertical_divider_changed_in_window (Lisp_Object specifier,
+                                   struct window *w,
                                    Lisp_Object oldval)
 {
   MARK_WINDOWS_CHANGED (w);
@@ -4606,7 +4876,7 @@ struct saved_window
   int pixel_width;
   int pixel_height;
   int hscroll;
-  int modeline_hscroll;
+  Charcount modeline_hscroll;
   int parent_index;           /* index into saved_windows */
   int prev_index;             /* index into saved_windows */
   char start_at_line_beg; /* boolean */
@@ -4621,8 +4891,8 @@ struct saved_window
 struct window_config
 {
   struct lcrecord_header header;
-  int frame_width;
-  int frame_height;
+  /*  int frame_width; No longer needed, JV
+      int frame_height; */
 #if 0 /* FSFmacs */
   Lisp_Object selected_frame;
 #endif
@@ -4630,6 +4900,7 @@ struct window_config
   Lisp_Object current_buffer;
   Lisp_Object minibuffer_scroll_window;
   Lisp_Object root_window;
+  int minibuf_height; /* 0 = no minibuffer, <0, size in lines, >0 in pixels */
   /* Record the values of window-min-width and window-min-height
      so that window sizes remain consistent with them.  */
   int min_width, min_height;
@@ -4642,36 +4913,35 @@ struct window_config
 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
-#define GC_WINDOW_CONFIGURATIONP(x) GC_RECORDP (x, window_configuration)
 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
 
 static Lisp_Object
-mark_window_config (Lisp_Object obj, void (*markobj) (Lisp_Object))
+mark_window_config (Lisp_Object obj)
 {
   struct window_config *config = XWINDOW_CONFIGURATION (obj);
   int i;
-  ((markobj) (config->current_window));
-  ((markobj) (config->current_buffer));
-  ((markobj) (config->minibuffer_scroll_window));
-  ((markobj) (config->root_window));
+  mark_object (config->current_window);
+  mark_object (config->current_buffer);
+  mark_object (config->minibuffer_scroll_window);
+  mark_object (config->root_window);
 
   for (i = 0; i < config->saved_windows_count; i++)
     {
       struct saved_window *s = SAVED_WINDOW_N (config, i);
-      ((markobj) (s->window));
-      ((markobj) (s->buffer));
-      ((markobj) (s->start));
-      ((markobj) (s->pointm));
-      ((markobj) (s->sb_point));
-      ((markobj) (s->mark));
+      mark_object (s->window);
+      mark_object (s->buffer);
+      mark_object (s->start);
+      mark_object (s->pointm);
+      mark_object (s->sb_point);
+      mark_object (s->mark);
 #if 0
       /* #### This looked like this. I do not see why specifier cached
         values should not be marked, as such specifiers as toolbars
         might have GC-able instances. Freed configs are not marked,
         aren't they?  -- kkm */
-      ((markobj) (s->dedicated));
+      mark_object (s->dedicated);
 #else
-#define WINDOW_SLOT(slot, compare) ((markobj) (s->slot))
+#define WINDOW_SLOT(slot, compare) mark_object (s->slot)
 #include "winslots.h"
 #endif
     }
@@ -4687,9 +4957,9 @@ sizeof_window_config_for_n_windows (int n)
 }
 
 static size_t
-sizeof_window_config (CONST void *h)
+sizeof_window_config (const void *h)
 {
-  CONST struct window_config *c = (CONST struct window_config *) h;
+  const struct window_config *c = (const struct window_config *) h;
   return sizeof_window_config_for_n_windows (c->saved_windows_count);
 }
 
@@ -4710,7 +4980,7 @@ DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
                                        window_configuration,
                                        mark_window_config,
                                        print_window_config,
-                                       0, 0, 0, sizeof_window_config,
+                                       0, 0, 0, 0, sizeof_window_config,
                                        struct window_config);
 
 
@@ -4761,9 +5031,10 @@ window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
        EQ (fig1->current_window,           fig2->current_window) &&
        EQ (fig1->current_buffer,           fig2->current_buffer) &&
        EQ (fig1->root_window,              fig2->root_window) &&
-       EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window) &&
+       EQ (fig1->minibuffer_scroll_window, fig2->minibuffer_scroll_window)))
+       /* &&
        fig1->frame_width  == fig2->frame_width &&
-       fig1->frame_height == fig2->frame_height))
+       fig1->frame_height == fig2->frame_height)) */
     return 0;
 
   for (i = 0; i < fig1->saved_windows_count; i++)
@@ -4859,8 +5130,15 @@ by `current-window-configuration' (which see).
   struct frame *f;
   struct gcpro gcpro1;
   Lisp_Object old_window_config;
-  int previous_frame_height;
-  int previous_frame_width;
+  /*  int previous_frame_height;
+      int previous_frame_width;*/
+  int previous_pixel_top;
+  int previous_pixel_height;
+  int previous_pixel_left;
+  int previous_pixel_width;
+  int previous_minibuf_height, previous_minibuf_top,previous_minibuf_width;
+  int real_font_height;
+  int converted_minibuf_height,target_minibuf_height;
   int specpdl_count = specpdl_depth ();
 
   GCPRO1 (configuration);
@@ -4924,7 +5202,35 @@ by `current-window-configuration' (which see).
       record_unwind_protect (free_window_configuration, old_window_config);
 
       mark_windows_in_use (f, 1);
-
+#ifdef BROKEN_SUBWINDOW_REDISPLAY
+      /* Force subwindows to be remapped. This is overkill but saves
+       us having to rely on the redisplay code to unmap any extant
+       subwindows.
+
+       #### It does cause some extra flashing though which we could
+       possibly avoid. So consider trying to get redisplay to work
+       correctly.
+
+       Removing the instances from the frame cache is wrong because
+       an instance is only put in the frame cache when it is
+       instantiated. So if we do this there is a chance that stuff
+       will never get put back in the frame cache. */
+      reset_frame_subwindow_instance_cache (f);
+#endif
+#if 0
+      /* JV: This is bogus,
+        First of all, the units are inconsistent. The frame sizes are measured
+        in characters but the window sizes are stored in pixels. So if a
+        font size change happened between saving and restoring, the
+        frame "sizes" maybe equal but the windows still should be
+        resized. This is tickled a lot by the new "character size
+        stays constant" policy in 21.0. It leads to very weird
+        glitches (and possibly crashes when asserts are tickled).
+
+        Just changing the units doesn't help because changing the
+        toolbar configuration can also change the pixel positions.
+        Luckily there is a much simpler way of doing this, see below.
+       */
       previous_frame_width = FRAME_WIDTH (f);
       previous_frame_height = FRAME_HEIGHT (f);
       /* If the frame has been resized since this window configuration was
@@ -4934,6 +5240,37 @@ by `current-window-configuration' (which see).
       if (config->frame_height != FRAME_HEIGHT (f)
          || config->frame_width != FRAME_WIDTH (f))
        change_frame_size (f, config->frame_height, config->frame_width, 0);
+#endif
+
+      previous_pixel_top = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top;
+      previous_pixel_height = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_height;
+      previous_pixel_left = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left;
+      previous_pixel_width = XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_width;
+
+      /* remember some properties of the minibuffer */
+
+      default_face_height_and_width (frame, &real_font_height, 0);
+      assert(real_font_height > 0);
+
+      if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
+       {
+         previous_minibuf_height
+           = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
+         previous_minibuf_top
+           = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_top;
+         previous_minibuf_width
+           = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_width;
+       }
+      else
+       {
+         previous_minibuf_height = 0;
+         previous_minibuf_top = 0;
+         previous_minibuf_width = 0;
+       }
+      converted_minibuf_height =
+       (previous_minibuf_height % real_font_height) == 0 ?
+       - (previous_minibuf_height / real_font_height ) :    /* lines */
+           previous_minibuf_height;   /* pixels */
 
       /* Temporarily avoid any problems with windows that are smaller
         than they are supposed to be.  */
@@ -4961,6 +5298,10 @@ by `current-window-configuration' (which see).
            w->glyph_cachels = Dynarr_new (glyph_cachel);
          if (!w->line_start_cache)
            w->line_start_cache = Dynarr_new (line_start_cache);
+         w->gutter_extent_modiff[0] = 0;
+         w->gutter_extent_modiff[1] = 0;
+         w->gutter_extent_modiff[2] = 0;
+         w->gutter_extent_modiff[3] = 0;
          w->dead = 0;
 
          if (p->parent_index >= 0)
@@ -5018,11 +5359,29 @@ by `current-window-configuration' (which see).
          w->hscroll = p->hscroll;
          w->modeline_hscroll = p->modeline_hscroll;
          w->line_cache_last_updated = Qzero;
+         /* When we restore a window's configuration, the identity of
+            the window hasn't actually changed - so there is no
+            reason why we shouldn't preserve the instance cache for
+            it - unless it was originally deleted. This will often
+            buy us something as we will not have to re-instantiate
+            all the instances. This is because this is an instance
+            cache - not a display cache. Preserving the display cache
+            would definitely be wrong.
+
+            We specifically want to do this for tabs, since for some
+            reason finding a file will cause the configuration to be
+            set. */
+         if (NILP (w->subwindow_instance_cache))
+           w->subwindow_instance_cache =
+             make_lisp_hash_table (30,
+                                   HASH_TABLE_KEY_VALUE_WEAK,
+                                   HASH_TABLE_EQ);
          SET_LAST_MODIFIED (w, 1);
          SET_LAST_FACECHANGE (w);
          w->config_mark = 0;
 
-#define WINDOW_SLOT(slot, compare) w->slot = p->slot;
+         /* #### Consider making the instance cache a winslot. */
+#define WINDOW_SLOT(slot, compare) w->slot = p->slot
 #include "winslots.h"
 
          /* Reinstall the saved buffer and pointers into it.  */
@@ -5100,16 +5459,67 @@ by `current-window-configuration' (which see).
         currently selected, or just set the selected window of the
         window config's frame. */
 
+#if 0
       /* Set the frame height to the value it had before this function.  */
       if (previous_frame_height != FRAME_HEIGHT (f)
          || previous_frame_width != FRAME_WIDTH (f))
        change_frame_size (f, previous_frame_height, previous_frame_width, 0);
+#endif
+      /* We just reset the size and position of the minibuffer, to its old
+        value, which needn't be valid. So we do some magic to see which value
+        to actually take. Then we set it.
+
+        The magic:
+        We take the old value if is in the same units but differs from the
+        current value.
+
+         #### Now we get more cases correct then ever before, but
+        are we treating all? For instance what if the frames minibuf window
+        is no longer the same one?
+      */
+      target_minibuf_height = previous_minibuf_height;
+      if (converted_minibuf_height &&
+         (converted_minibuf_height * config->minibuf_height) > 0 &&
+         (converted_minibuf_height !=  config->minibuf_height))
+       {
+         target_minibuf_height = config->minibuf_height < 0 ?
+           - (config->minibuf_height * real_font_height) :
+           config->minibuf_height;
+         target_minibuf_height =
+           max(target_minibuf_height,real_font_height);
+       }
+      if (previous_minibuf_height)
+       {
+         XWINDOW (FRAME_MINIBUF_WINDOW (f))->pixel_top
+           = previous_minibuf_top -
+                 (target_minibuf_height - previous_minibuf_height);
+         set_window_pixheight (FRAME_MINIBUF_WINDOW (f),
+                               target_minibuf_height, 0);
+         set_window_pixwidth  (FRAME_MINIBUF_WINDOW (f),
+                           previous_minibuf_width, 0);
+       }
+
+      /* This is a better way to deal with frame resizing, etc.
+        What we _actually_ want is for the old (just restored)
+        root window to fit
+        into the place of the new one. So we just do that. Simple! */
+      XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_top = previous_pixel_top;
+      /* Note that this function also updates the subwindow
+        "pixel_top"s */
+      set_window_pixheight (FRAME_ROOT_WINDOW (f),
+         previous_pixel_height -
+                 (target_minibuf_height - previous_minibuf_height), 0);
+      XWINDOW (FRAME_ROOT_WINDOW (f))->pixel_left = previous_pixel_left;
+      /* Note that this function also updates the subwindow
+        "pixel_left"s */
+      set_window_pixwidth (FRAME_ROOT_WINDOW (f), previous_pixel_width, 0);
 
       /* If restoring in the current frame make the window current,
         otherwise just update the frame selected_window slot to be
         the restored current_window. */
       if (f == selected_frame ())
        {
+#if 0
          /* When using `pop-window-configuration', often the minibuffer
             ends up as the selected window even though it's not active ...
             I really don't know the cause of this, but it should never
@@ -5118,15 +5528,25 @@ by `current-window-configuration' (which see).
             #### Find out why this is really going wrong. */
          if (!minibuf_level &&
              MINI_WINDOW_P (XWINDOW (config->current_window)))
-           Fselect_window (Fnext_window (config->current_window,
-                                         Qnil, Qnil, Qnil),
-                            Qnil);
+           window_to_select = Fnext_window (config->current_window,
+                                            Qnil, Qnil, Qnil);
          else
-           Fselect_window (config->current_window, Qnil);
+           window_to_select = config->current_window;
+#endif
+         /* Do this last so that buffer stacking is calculated
+            correctly. */
+         Fselect_window (config->current_window, Qnil);
+
          if (!NILP (new_current_buffer))
-           Fset_buffer (new_current_buffer);
+           {
+             Fset_buffer (new_current_buffer);
+             Frecord_buffer (new_current_buffer);
+           }
          else
-           Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
+           {
+             Fset_buffer (XWINDOW (config->current_window)->buffer);
+             Frecord_buffer (XWINDOW (config->current_window)->buffer);
+           }
        }
       else
        set_frame_selected_window (f, config->current_window);
@@ -5246,7 +5666,7 @@ save_window_save (Lisp_Object window, struct window_config *config, int i)
       p->hscroll = w->hscroll;
       p->modeline_hscroll = w->modeline_hscroll;
 
-#define WINDOW_SLOT(slot, compare) p->slot = w->slot;
+#define WINDOW_SLOT(slot, compare) p->slot = w->slot
 #include "winslots.h"
 
       if (!NILP (w->buffer))
@@ -5319,6 +5739,8 @@ its value is -not- saved.
   struct frame *f = decode_frame (frame);
   struct window_config *config;
   int n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
+  int minibuf_height;
+  int real_font_height;
 
   if (n_windows <= countof (Vwindow_configuration_free_list))
     config = XWINDOW_CONFIGURATION (allocate_managed_lcrecord
@@ -5328,12 +5750,19 @@ its value is -not- saved.
     /* More than ten windows; just allocate directly */
     config = (struct window_config *)
       alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
-                     lrecord_window_configuration);
+                     &lrecord_window_configuration);
   XSETWINDOW_CONFIGURATION (result, config);
-
+  /*
   config->frame_width = FRAME_WIDTH (f);
-  config->frame_height = FRAME_HEIGHT (f);
-  config->current_window = FRAME_SELECTED_WINDOW (f);
+  config->frame_height = FRAME_HEIGHT (f); */
+  /* When using `push-window-configuration', often the minibuffer ends
+     up as the selected window because functions run as the result of
+     user interaction e.g. hyper-apropos. It seems to me the sensible
+     thing to do is not record the minibuffer here. */
+  if (FRAME_MINIBUF_ONLY_P (f) || minibuf_level)
+    config->current_window = FRAME_SELECTED_WINDOW (f);
+  else
+    config->current_window = FRAME_LAST_NONMINIBUF_WINDOW (f);
   XSETBUFFER (config->current_buffer, current_buffer);
   config->minibuffer_scroll_window = Vminibuffer_scroll_window;
   config->root_window = FRAME_ROOT_WINDOW (f);
@@ -5341,6 +5770,22 @@ its value is -not- saved.
   config->min_width = window_min_width;
   config->saved_windows_count = n_windows;
   save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
+
+  /* save the minibuffer height using the heuristics from
+     change_frame_size_1 */
+
+  XSETFRAME (frame, f); /* frame could have been nil ! */
+  default_face_height_and_width (frame, &real_font_height, 0);
+  assert(real_font_height > 0);
+
+  if (FRAME_HAS_MINIBUF_P (f) && ! FRAME_MINIBUF_ONLY_P (f))
+    minibuf_height = XWINDOW(FRAME_MINIBUF_WINDOW(f))->pixel_height;
+  else
+    minibuf_height = 0;
+  config->minibuf_height = (minibuf_height % real_font_height) == 0 ?
+    - (minibuf_height / real_font_height ) :    /* lines */
+    minibuf_height;   /* pixels */
+
   return result;
 }
 
@@ -5370,6 +5815,78 @@ Does not restore the value of point in current buffer.
   return unbind_to (speccount, val);
 }
 
+DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /*
+Return the horizontal pixel position of POS in window.
+Beginning of line is column 0. This is calculated using the redisplay
+display tables.  If WINDOW is nil, the current window is assumed.
+If POS is nil, point is assumed. Note that POS must be visible for
+a non-nil result to be returned.
+*/
+       (window, pos))
+{
+  struct window* w = decode_window (window);
+  display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
+
+  struct display_line *dl = 0;
+  struct display_block *db = 0;
+  struct rune* rb = 0;
+  int y = w->last_point_y[CURRENT_DISP];
+  int x = w->last_point_x[CURRENT_DISP];
+
+  if (MINI_WINDOW_P (w))
+    return Qnil;
+
+  if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos))
+    {
+      int first_line, i;
+      Bufpos point;
+
+      if (NILP (pos))
+       pos = Fwindow_point (window);
+
+      CHECK_INT (pos);
+      point = XINT (pos);
+
+      if (Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
+       first_line = 1;
+      else
+       first_line = 0;
+
+      for (i = first_line; i < Dynarr_length (dla); i++)
+       {
+         dl = Dynarr_atp (dla, i);
+         /* find the vertical location first */
+         if (point >= dl->bufpos && point <= dl->end_bufpos)
+           {
+             db = get_display_block_from_line (dl, TEXT);
+             for (i = 0; i < Dynarr_length (db->runes); i++)
+               {
+                 rb = Dynarr_atp (db->runes, i);
+                 if (point <= rb->bufpos)
+                   goto found_bufpos;
+               }
+             return Qnil;
+           }
+       }
+      return Qnil;
+    found_bufpos:
+      ;
+    }
+  else
+    {
+      /* optimized case */
+      dl = Dynarr_atp (dla, y);
+      db = get_display_block_from_line (dl, TEXT);
+
+      if (x >= Dynarr_length (db->runes))
+       return Qnil;
+
+      rb = Dynarr_atp (db->runes, x);
+    }
+
+  return make_int (rb->xpos - WINDOW_LEFT (w));
+}
+
 \f
 #ifdef DEBUG_XEMACS
 /* This is short and simple in elisp, but... it was written to debug
@@ -5385,15 +5902,15 @@ debug_print_window (Lisp_Object window, int level)
     child = Fwindow_first_hchild (window);
 
   for (i = level; i > 0; i--)
-    putc ('\t', stderr);
+    stderr_out ("\t");
 
-  fputs ("#<window", stderr);
+  stderr_out ("#<window");
   {
     Lisp_Object buffer = XWINDOW (window)->buffer;
     if (!NILP (buffer) && BUFFERP (buffer))
-      fprintf (stderr, " on %s", XSTRING_DATA (XBUFFER (buffer)->name));
+      stderr_out (" on %s", XSTRING_DATA (XBUFFER (buffer)->name));
   }
-  fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
+  stderr_out (" 0x%x>", XWINDOW (window)->header.uid);
 
   while (!NILP (child))
     {
@@ -5419,11 +5936,12 @@ debug_print_windows (struct frame *f)
 void
 syms_of_window (void)
 {
+  INIT_LRECORD_IMPLEMENTATION (window);
+  INIT_LRECORD_IMPLEMENTATION (window_configuration);
+
   defsymbol (&Qwindowp, "windowp");
   defsymbol (&Qwindow_live_p, "window-live-p");
   defsymbol (&Qwindow_configurationp, "window-configuration-p");
-  defsymbol (&Qscroll_up, "scroll-up");
-  defsymbol (&Qscroll_down, "scroll-down");
   defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
   defsymbol (&Qdisplay_buffer, "display-buffer");
 
@@ -5439,6 +5957,7 @@ syms_of_window (void)
 #endif
 
   DEFSUBR (Fselected_window);
+  DEFSUBR (Flast_nonminibuf_window);
   DEFSUBR (Fminibuffer_window);
   DEFSUBR (Fwindow_minibuffer_p);
   DEFSUBR (Fwindowp);
@@ -5449,6 +5968,7 @@ syms_of_window (void)
   DEFSUBR (Fwindow_previous_child);
   DEFSUBR (Fwindow_parent);
   DEFSUBR (Fwindow_lowest_p);
+  DEFSUBR (Fwindow_truncated_p);
   DEFSUBR (Fwindow_highest_p);
   DEFSUBR (Fwindow_leftmost_p);
   DEFSUBR (Fwindow_rightmost_p);
@@ -5458,26 +5978,27 @@ syms_of_window (void)
   DEFSUBR (Fwindow_height);
   DEFSUBR (Fwindow_displayed_height);
   DEFSUBR (Fwindow_width);
+  DEFSUBR (Fwindow_full_width);
   DEFSUBR (Fwindow_pixel_height);
   DEFSUBR (Fwindow_pixel_width);
+  DEFSUBR (Fwindow_text_area_height);
   DEFSUBR (Fwindow_text_area_pixel_height);
   DEFSUBR (Fwindow_displayed_text_pixel_height);
   DEFSUBR (Fwindow_text_area_pixel_width);
   DEFSUBR (Fwindow_hscroll);
-#ifdef MODELINE_IS_SCROLLABLE
+  DEFSUBR (Fset_window_hscroll);
   DEFSUBR (Fmodeline_hscroll);
   DEFSUBR (Fset_modeline_hscroll);
-#endif /* MODELINE_IS_SCROLLABLE */
 #if 0 /* bogus FSF crock */
   DEFSUBR (Fwindow_redisplay_end_trigger);
   DEFSUBR (Fset_window_redisplay_end_trigger);
 #endif
-  DEFSUBR (Fset_window_hscroll);
   DEFSUBR (Fwindow_pixel_edges);
   DEFSUBR (Fwindow_text_area_pixel_edges);
   DEFSUBR (Fwindow_point);
   DEFSUBR (Fwindow_start);
   DEFSUBR (Fwindow_end);
+  DEFSUBR (Fwindow_last_line_visible_height);
   DEFSUBR (Fset_window_point);
   DEFSUBR (Fset_window_start);
   DEFSUBR (Fwindow_dedicated_p);
@@ -5517,14 +6038,30 @@ syms_of_window (void)
   DEFSUBR (Fset_window_configuration);
   DEFSUBR (Fcurrent_window_configuration);
   DEFSUBR (Fsave_window_excursion);
+  DEFSUBR (Fcurrent_pixel_column);
 }
 
 void
-vars_of_window (void)
+reinit_vars_of_window (void)
 {
+  int i;
   /* Make sure all windows get marked */
   minibuf_window = Qnil;
-  staticpro (&minibuf_window);
+  staticpro_nodump (&minibuf_window);
+
+  for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
+    {
+      Vwindow_configuration_free_list[i] =
+       make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
+                           &lrecord_window_configuration);
+      staticpro_nodump (&Vwindow_configuration_free_list[i]);
+    }
+}
+
+void
+vars_of_window (void)
+{
+  reinit_vars_of_window ();
 
   DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
 *Non-nil means to scroll if point lands on a line which is clipped.
@@ -5542,6 +6079,7 @@ The function is called with one argument, the buffer to be displayed.
 Used by `with-output-to-temp-buffer'.
 If this function is used, then it must do the entire job of showing
 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
+\(`temp-buffer-show-hook' is obsolete.  Do not use in new code.)
 */ );
   Vtemp_buffer_show_function = Qnil;
 
@@ -5555,6 +6093,13 @@ If non-nil, this is a buffer and \\[scroll-other-window] should scroll its windo
 */ );
   Vother_window_scroll_buffer = Qnil;
 
+  DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /*
+*Number of pixels to scroll by per requested line.
+If nil then normal line scrolling occurs regardless of line height.
+If t then scrolling is done in increments equal to the height of the default face.
+*/ );
+  Vwindow_pixel_scroll_increment = Qt;
+
   DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
 *Number of lines of continuity when scrolling by screenfuls.
 */ );
@@ -5569,18 +6114,6 @@ If non-nil, this is a buffer and \\[scroll-other-window] should scroll its windo
 *Delete any window less than this wide.
 */ );
   window_min_width = 10;
-
-  {
-    int i;
-
-    for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
-      {
-       Vwindow_configuration_free_list[i] =
-         make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
-                             lrecord_window_configuration);
-       staticpro (&Vwindow_configuration_free_list[i]);
-      }
-  }
 }
 
 void
@@ -5601,11 +6134,10 @@ This is a specifier; use `set-specifier' to change it.
   Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
                          Qnil, Qnil, Qnil);
   set_specifier_caching (Vmodeline_shadow_thickness,
-                        slot_offset (struct window,
-                                     modeline_shadow_thickness),
+                        offsetof (struct window, modeline_shadow_thickness),
                         modeline_shadow_thickness_changed,
                         0, 0);
-  
+
   DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
 *Whether the modeline should be displayed.
 This is a specifier; use `set-specifier' to change it.
@@ -5614,8 +6146,7 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_fallback (Vhas_modeline_p,
                          list1 (Fcons (Qnil, Qt)));
   set_specifier_caching (Vhas_modeline_p,
-                        slot_offset (struct window,
-                                     has_modeline_p),
+                        offsetof (struct window, has_modeline_p),
                         /* #### It's strange that we need a special
                            flag to indicate that the shadow-thickness
                            has changed, but not one to indicate that
@@ -5637,13 +6168,13 @@ This is a specifier; use `set-specifier' to change it.
   set_specifier_fallback (Vvertical_divider_always_visible_p,
                          list1 (Fcons (Qnil, Qt)));
   set_specifier_caching (Vvertical_divider_always_visible_p,
-                        slot_offset (struct window,
-                                     vertical_divider_always_visible_p),
+                        offsetof (struct window,
+                                  vertical_divider_always_visible_p),
                         vertical_divider_changed_in_window,
                         0, 0);
 
   DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /*
-*How thick to draw 3D shadows around vertical dividers. 
+*How thick to draw 3D shadows around vertical dividers.
 This is a specifier; use `set-specifier' to change it.
 */ );
   Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger);
@@ -5652,8 +6183,8 @@ This is a specifier; use `set-specifier' to change it.
   Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2),
                          Qnil, Qnil, Qnil);
   set_specifier_caching (Vvertical_divider_shadow_thickness,
-                        slot_offset (struct window,
-                                     vertical_divider_shadow_thickness),
+                        offsetof (struct window,
+                                  vertical_divider_shadow_thickness),
                         vertical_divider_changed_in_window,
                         0, 0);
   DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /*
@@ -5683,8 +6214,8 @@ This is a specifier; use `set-specifier' to change it.
     set_specifier_fallback (Vvertical_divider_line_width, fb);
   }
   set_specifier_caching (Vvertical_divider_line_width,
-                         slot_offset (struct window,
-                                     vertical_divider_line_width),
+                         offsetof (struct window,
+                                  vertical_divider_line_width),
                         vertical_divider_changed_in_window,
                          0, 0);
 
@@ -5713,8 +6244,7 @@ This is a specifier; use `set-specifier' to change it.
     set_specifier_fallback (Vvertical_divider_spacing, fb);
   }
   set_specifier_caching (Vvertical_divider_spacing,
-                        slot_offset (struct window,
-                                     vertical_divider_spacing),
+                        offsetof (struct window, vertical_divider_spacing),
                         vertical_divider_changed_in_window,
                         0, 0);
 }