]> code.delx.au - gnu-emacs/blobdiff - src/window.c
Port USE_STACK_LISP_OBJECTS fix to Clang
[gnu-emacs] / src / window.c
index ad5ac79bd8e7e286c36093ae4e4fd75ec1765aa2..8953d3cec00299c9bd2db6ce6b28b888a0ffa04d 100644 (file)
@@ -1,6 +1,6 @@
 /* Window creation, deletion and examination for GNU Emacs.
    Does not include redisplay.
-   Copyright (C) 1985-1987, 1993-1998, 2000-2015 Free Software
+   Copyright (C) 1985-1987, 1993-1998, 2000-2016 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -23,11 +23,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 
 #include "lisp.h"
-#include "character.h"
 #include "buffer.h"
 #include "keyboard.h"
 #include "keymap.h"
-#include "menu.h"
 #include "frame.h"
 #include "window.h"
 #include "commands.h"
@@ -36,8 +34,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "disptab.h"
 #include "dispextern.h"
 #include "blockinput.h"
-#include "intervals.h"
 #include "termhooks.h"         /* For FRAME_TERMINAL.  */
+#include "xwidget.h"
 #ifdef HAVE_WINDOW_SYSTEM
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -208,6 +206,20 @@ wset_combination (struct window *w, bool horflag, Lisp_Object val)
     w->horizontal = horflag;
 }
 
+static void
+wset_update_mode_line (struct window *w)
+{
+  /* If this window is the selected window on its frame, set the
+     global variable update_mode_lines, so that x_consider_frame_title
+     will consider this frame's title for redisplay.  */
+  Lisp_Object fselected_window = XFRAME (WINDOW_FRAME (w))->selected_window;
+
+  if (WINDOWP (fselected_window) && XWINDOW (fselected_window) == w)
+    update_mode_lines = 42;
+  else
+    w->update_mode_line = true;
+}
+
 /* True if leaf window W doesn't reflect the actual state
    of displayed buffer due to its text or overlays change.  */
 
@@ -641,7 +653,7 @@ DEFUN ("window-combination-limit", Fwindow_combination_limit, Swindow_combinatio
 WINDOW must be a valid window used in horizontal or vertical combination.
 If the return value is nil, child windows of WINDOW can be recombined with
 WINDOW's siblings.  A return value of t means that child windows of
-WINDOW are never \(re-)combined with WINDOW's siblings.  */)
+WINDOW are never (re-)combined with WINDOW's siblings.  */)
   (Lisp_Object window)
 {
   struct window *w;
@@ -658,7 +670,7 @@ DEFUN ("set-window-combination-limit", Fset_window_combination_limit, Sset_windo
 WINDOW must be a valid window used in horizontal or vertical combination.
 If LIMIT is nil, child windows of WINDOW can be recombined with WINDOW's
 siblings.  LIMIT t means that child windows of WINDOW are never
-\(re-)combined with WINDOW's siblings.  Other values are reserved for
+(re-)combined with WINDOW's siblings.  Other values are reserved for
 future use.  */)
   (Lisp_Object window, Lisp_Object limit)
 {
@@ -1101,186 +1113,6 @@ end-trigger value is reset to nil.  */)
   return value;
 }
 
-DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0,
-       doc: /* Return a list of the edge coordinates of WINDOW.
-WINDOW must be a valid window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM).  TOP and BOTTOM
-count by lines, and LEFT and RIGHT count by columns, all relative to 0,
-0 at top left corner of frame.
-
-RIGHT is one more than the rightmost column occupied by WINDOW.  BOTTOM
-is one more than the bottommost row occupied by WINDOW.  The edges
-include the space used by WINDOW's scroll bar, display margins, fringes,
-header line, and/or mode line.  For the edges of just the text area, use
-`window-inside-edges'.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_valid_window (window);
-
-  return list4i (WINDOW_LEFT_EDGE_COL (w), WINDOW_TOP_EDGE_LINE (w),
-                WINDOW_RIGHT_EDGE_COL (w), WINDOW_BOTTOM_EDGE_LINE (w));
-}
-
-DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge pixel coordinates of WINDOW.
-WINDOW must be a valid window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM), all relative to
-0, 0 at the top left corner of the frame.
-
-RIGHT is one more than the rightmost x position occupied by WINDOW.
-BOTTOM is one more than the bottommost y position occupied by WINDOW.
-The pixel edges include the space used by WINDOW's scroll bar, display
-margins, fringes, header line, and/or mode line.  For the pixel edges
-of just the text area, use `window-inside-pixel-edges'.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_valid_window (window);
-
-  return list4i (WINDOW_LEFT_EDGE_X (w), WINDOW_TOP_EDGE_Y (w),
-                WINDOW_RIGHT_EDGE_X (w), WINDOW_BOTTOM_EDGE_Y (w));
-}
-
-static void
-calc_absolute_offset (struct window *w, int *add_x, int *add_y)
-{
-  struct frame *f = XFRAME (w->frame);
-  *add_y = f->top_pos;
-#ifdef FRAME_MENUBAR_HEIGHT
-  *add_y += FRAME_MENUBAR_HEIGHT (f);
-#endif
-#ifdef FRAME_TOOLBAR_TOP_HEIGHT
-  *add_y += FRAME_TOOLBAR_TOP_HEIGHT (f);
-#elif defined (FRAME_TOOLBAR_HEIGHT)
-  *add_y += FRAME_TOOLBAR_HEIGHT (f);
-#endif
-#ifdef FRAME_NS_TITLEBAR_HEIGHT
-  *add_y += FRAME_NS_TITLEBAR_HEIGHT (f);
-#endif
-  *add_x = f->left_pos;
-#ifdef FRAME_TOOLBAR_LEFT_WIDTH
-  *add_x += FRAME_TOOLBAR_LEFT_WIDTH (f);
-#endif
-}
-
-DEFUN ("window-absolute-pixel-edges", Fwindow_absolute_pixel_edges,
-       Swindow_absolute_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge pixel coordinates of WINDOW.
-WINDOW must be a valid window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM), all relative to
-0, 0 at the top left corner of the display.
-
-RIGHT is one more than the rightmost x position occupied by WINDOW.
-BOTTOM is one more than the bottommost y position occupied by WINDOW.
-The pixel edges include the space used by WINDOW's scroll bar, display
-margins, fringes, header line, and/or mode line.  For the pixel edges
-of just the text area, use `window-inside-absolute-pixel-edges'.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_valid_window (window);
-  int add_x, add_y;
-
-  calc_absolute_offset (w, &add_x, &add_y);
-
-  return list4i (WINDOW_LEFT_EDGE_X (w) + add_x,
-                WINDOW_TOP_EDGE_Y (w) + add_y,
-                WINDOW_RIGHT_EDGE_X (w) + add_x,
-                WINDOW_BOTTOM_EDGE_Y (w) + add_y);
-}
-
-DEFUN ("window-inside-edges", Fwindow_inside_edges, Swindow_inside_edges, 0, 1, 0,
-       doc: /* Return a list of the edge coordinates of WINDOW.
-WINDOW must be a live window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM).  TOP and BOTTOM
-count by lines, and LEFT and RIGHT count by columns, all relative to 0,
-0 at top left corner of frame.
-
-RIGHT is one more than the rightmost column of WINDOW's text area.
-BOTTOM is one more than the bottommost row of WINDOW's text area.  The
-inside edges do not include the space used by the WINDOW's scroll bar,
-display margins, fringes, header line, and/or mode line.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_live_window (window);
-
-  return list4i ((WINDOW_BOX_LEFT_EDGE_COL (w)
-                 + WINDOW_LEFT_MARGIN_COLS (w)
-                 + ((WINDOW_LEFT_FRINGE_WIDTH (w)
-                     + WINDOW_FRAME_COLUMN_WIDTH (w) - 1)
-                    / WINDOW_FRAME_COLUMN_WIDTH (w))),
-                (WINDOW_TOP_EDGE_LINE (w)
-                 + WINDOW_HEADER_LINE_LINES (w)),
-                (WINDOW_BOX_RIGHT_EDGE_COL (w)
-                 - WINDOW_RIGHT_MARGIN_COLS (w)
-                 - ((WINDOW_RIGHT_FRINGE_WIDTH (w)
-                     + WINDOW_FRAME_COLUMN_WIDTH (w) - 1)
-                    / WINDOW_FRAME_COLUMN_WIDTH (w))),
-                (WINDOW_BOTTOM_EDGE_LINE (w)
-                 - WINDOW_MODE_LINE_LINES (w)));
-}
-
-DEFUN ("window-inside-pixel-edges", Fwindow_inside_pixel_edges, Swindow_inside_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge pixel coordinates of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM), all relative to
-(0,0) at the top left corner of the frame's window area.
-
-RIGHT is one more than the rightmost x position of WINDOW's text area.
-BOTTOM is one more than the bottommost y position of WINDOW's text area.
-The inside edges do not include the space used by WINDOW's scroll bar,
-display margins, fringes, header line, and/or mode line.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_live_window (window);
-
-  return list4i ((WINDOW_BOX_LEFT_EDGE_X (w)
-                 + WINDOW_LEFT_MARGIN_WIDTH (w)
-                 + WINDOW_LEFT_FRINGE_WIDTH (w)),
-                (WINDOW_TOP_EDGE_Y (w)
-                 + WINDOW_HEADER_LINE_HEIGHT (w)),
-                (WINDOW_BOX_RIGHT_EDGE_X (w)
-                 - WINDOW_RIGHT_MARGIN_WIDTH (w)
-                 - WINDOW_RIGHT_FRINGE_WIDTH (w)),
-                (WINDOW_BOTTOM_EDGE_Y (w)
-                 - WINDOW_MODE_LINE_HEIGHT (w)));
-}
-
-DEFUN ("window-inside-absolute-pixel-edges",
-       Fwindow_inside_absolute_pixel_edges,
-       Swindow_inside_absolute_pixel_edges, 0, 1, 0,
-       doc: /* Return a list of the edge pixel coordinates of WINDOW's text area.
-WINDOW must be a live window and defaults to the selected one.
-
-The returned list has the form (LEFT TOP RIGHT BOTTOM), all relative to
-(0,0) at the top left corner of the frame's window area.
-
-RIGHT is one more than the rightmost x position of WINDOW's text area.
-BOTTOM is one more than the bottommost y position of WINDOW's text area.
-The inside edges do not include the space used by WINDOW's scroll bar,
-display margins, fringes, header line, and/or mode line.  */)
-  (Lisp_Object window)
-{
-  register struct window *w = decode_live_window (window);
-  int add_x, add_y;
-
-  calc_absolute_offset (w, &add_x, &add_y);
-
-  return list4i ((WINDOW_BOX_LEFT_EDGE_X (w)
-                 + WINDOW_LEFT_MARGIN_WIDTH (w)
-                 + WINDOW_LEFT_FRINGE_WIDTH (w) + add_x),
-                (WINDOW_TOP_EDGE_Y (w)
-                 + WINDOW_HEADER_LINE_HEIGHT (w) + add_y),
-                (WINDOW_BOX_RIGHT_EDGE_X (w)
-                 - WINDOW_RIGHT_MARGIN_WIDTH (w)
-                 - WINDOW_RIGHT_FRINGE_WIDTH (w) + add_x),
-                (WINDOW_BOTTOM_EDGE_Y (w)
-                 - WINDOW_MODE_LINE_HEIGHT (w) + add_y));
-}
-
 /* Test if the character at column X, row Y is within window W.
    If it is not, return ON_NOTHING;
    if it is on the window's vertical divider, return
@@ -1471,10 +1303,18 @@ window_relative_x_coord (struct window *w, enum window_part part, int x)
              + window_box_width (w, RIGHT_MARGIN_AREA)
              + ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w))
                 ? WINDOW_RIGHT_FRINGE_WIDTH (w) : 0));
-    }
 
-  /* ON_SCROLL_BAR, ON_NOTHING, and ON_VERTICAL_BORDER:  */
-  return 0;
+    case ON_NOTHING:
+    case ON_VERTICAL_BORDER:
+    case ON_VERTICAL_SCROLL_BAR:
+    case ON_HORIZONTAL_SCROLL_BAR:
+    case ON_RIGHT_DIVIDER:
+    case ON_BOTTOM_DIVIDER:
+      return 0;
+
+    default:
+      emacs_abort ();
+    }
 }
 
 
@@ -1484,7 +1324,7 @@ DEFUN ("coordinates-in-window-p", Fcoordinates_in_window_p,
 WINDOW must be a live window and defaults to the selected one.
 COORDINATES is a cons of the form (X . Y), X and Y being distances
 measured in characters from the upper-left corner of the frame.
-\(0 . 0) denotes the character in the upper left corner of the
+(0 . 0) denotes the character in the upper left corner of the
 frame.
 If COORDINATES are in the text portion of WINDOW,
    the coordinates relative to the window are returned.
@@ -1841,7 +1681,7 @@ overriding motion of point in order to display at this exact start.  */)
   w->start_at_line_beg = false;
   if (NILP (noforce))
     w->force_start = true;
-  w->update_mode_line = true;
+  wset_update_mode_line (w);
   /* Bug#15957.  */
   w->window_end_valid = false;
   wset_redisplay (w);
@@ -1858,8 +1698,10 @@ Return nil if that position is scrolled vertically out of view.  If a
 character is only partially visible, nil is returned, unless the
 optional argument PARTIALLY is non-nil.  If POS is only out of view
 because of horizontal scrolling, return non-nil.  If POS is t, it
-specifies the position of the last visible glyph in WINDOW.  POS
-defaults to point in WINDOW; WINDOW defaults to the selected window.
+specifies either the first position displayed on the last visible
+screen line in WINDOW, or the end-of-buffer position, whichever comes
+first.  POS defaults to point in WINDOW; WINDOW defaults to the
+selected window.
 
 If POS is visible, return t if PARTIALLY is nil; if PARTIALLY is non-nil,
 the return value is a list of 2 or 6 elements (X Y [RTOP RBOT ROWH VPOS]),
@@ -1868,7 +1710,7 @@ of the window.  The remaining elements are omitted if the character after
 POS is fully visible; otherwise, RTOP and RBOT are the number of pixels
 off-window at the top and bottom of the screen line ("row") containing
 POS, ROWH is the visible height of that row, and VPOS is the row number
-\(zero-based).  */)
+(zero-based).  */)
   (Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
 {
   struct window *w;
@@ -2813,7 +2655,6 @@ window_loop (enum window_loop type, Lisp_Object obj, bool mini,
   Lisp_Object window, windows, best_window, frame_arg;
   bool frame_best_window_flag = false;
   struct frame *f;
-  struct gcpro gcpro1;
 
   /* If we're only looping through windows on a particular frame,
      frame points to that frame.  If we're looping through windows
@@ -2847,7 +2688,6 @@ window_loop (enum window_loop type, Lisp_Object obj, bool mini,
     window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
 
   windows = window_list_1 (window, mini ? Qt : Qnil, frame_arg);
-  GCPRO1 (windows);
   best_window = Qnil;
 
   for (; CONSP (windows); windows = XCDR (windows))
@@ -2875,7 +2715,7 @@ window_loop (enum window_loop type, Lisp_Object obj, bool mini,
              {
                if (EQ (window, selected_window))
                  /* Preferably return the selected window.  */
-                 RETURN_UNGCPRO (window);
+                 return window;
                else if (EQ (XWINDOW (window)->frame, selected_frame)
                         && !frame_best_window_flag)
                  /* Prefer windows on the current frame (but don't
@@ -2941,7 +2781,6 @@ window_loop (enum window_loop type, Lisp_Object obj, bool mini,
          }
     }
 
-  UNGCPRO;
   return best_window;
 }
 
@@ -3447,7 +3286,8 @@ set_window_buffer (Lisp_Object window, Lisp_Object buffer,
   /* Maybe we could move this into the `if' but it's not obviously safe and
      I doubt it's worth the trouble.  */
   wset_redisplay (w);
-  w->update_mode_line = true;
+
+  wset_update_mode_line (w);
 
   /* We must select BUFFER to run the window-scroll-functions and to look up
      the buffer-local value of Vwindow_point_insertion_type.  */
@@ -4131,9 +3971,11 @@ values.  */)
 }
 
 
-/* Resize frame F's windows when number of lines of F is set to SIZE.
-   HORFLAG means resize windows when number of columns of F is set to
-   SIZE.  PIXELWISE means to interpret SIZE as pixels.  */
+/* Resize frame F's windows when F's width or height is set to SIZE.
+   If HORFLAG is zero, F's width was set to SIZE, otherwise its height
+   was set.  SIZE is interpreted in F's canonical character units
+   (a.k.a. "columns" or "lines"), unless PIXELWISE is non-zero, which
+   means to interpret SIZE in pixel units.  */
 void
 resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
 {
@@ -4144,7 +3986,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
   /* old_size is the old size of the frame's root window.  */
   int old_size = horflag ? r->total_cols : r->total_lines;
   int old_pixel_size = horflag ? r->pixel_width : r->pixel_height;
-  int old_pixel_top = r->pixel_top;
   /* new_size is the new size of the frame's root window.  */
   int new_size, new_pixel_size;
   int unit = horflag ? FRAME_COLUMN_WIDTH (f) : FRAME_LINE_HEIGHT (f);
@@ -4174,11 +4015,8 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
       new_pixel_size = new_size * unit;
     }
 
-  r->top_line = FRAME_TOP_MARGIN (f);
-  r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
-
   if (new_pixel_size == old_pixel_size
-      && r->pixel_top == old_pixel_top)
+      && (horflag || r->pixel_top == FRAME_TOP_MARGIN_HEIGHT (f)))
     ;
   else if (WINDOW_LEAF_P (r))
     /* For a leaf root window just set the size.  */
@@ -4189,6 +4027,9 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
       }
     else
       {
+       r->top_line = FRAME_TOP_MARGIN (f);
+       r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
+
        r->total_lines = new_size;
        r->pixel_height = new_pixel_size;
       }
@@ -4196,6 +4037,12 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
     {
       Lisp_Object delta;
 
+      if (!horflag)
+       {
+         r->top_line = FRAME_TOP_MARGIN (f);
+         r->pixel_top = FRAME_TOP_MARGIN_HEIGHT (f);
+       }
+
       if (pixelwise)
        XSETINT (delta, new_pixel_size - old_pixel_size);
       else
@@ -4220,37 +4067,6 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
            {
              window_resize_apply (r, horflag);
              window_pixel_to_total (r->frame, horflag ? Qt : Qnil);
-#if false /* Let's try without safe sizes and/or killing other windows.  */
-           }
-         else
-           {
-             /* Finally, try with "safe" minimum sizes.  */
-             resize_root_window (root, delta, horflag ? Qt : Qnil, Qsafe,
-                                 pixelwise ? Qt : Qnil);
-             if (window_resize_check (r, horflag)
-                 && new_pixel_size == XINT (r->new_pixel))
-               {
-                 window_resize_apply (r, horflag);
-                 window_pixel_to_total (r->frame, horflag ? Qt : Qnil);
-               }
-             else
-               {
-                 /* We lost.  Delete all windows but the frame's
-                    selected one.  */
-                 root = f->selected_window;
-                 Fdelete_other_windows_internal (root, Qnil);
-                 if (horflag)
-                   {
-                     XWINDOW (root)->total_cols = new_size;
-                     XWINDOW (root)->pixel_width = new_pixel_size;
-                   }
-                 else
-                   {
-                     XWINDOW (root)->total_lines = new_size;
-                     XWINDOW (root)->pixel_height = new_pixel_size;
-                   }
-               }
-#endif /* false */
            }
        }
     }
@@ -4260,7 +4076,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
       m = XWINDOW (mini);
       if (horflag)
        {
-         m->total_cols = size;
+         m->total_cols = new_size;
          m->pixel_width = new_pixel_size;
        }
       else
@@ -4273,6 +4089,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag, bool pixelwise)
        }
     }
 
+  FRAME_WINDOW_SIZES_CHANGED (f) = true;
   fset_redisplay (f);
 }
 
@@ -4554,6 +4371,7 @@ Signal an error when WINDOW is the only window on its frame.  */)
 
       /* Block input.  */
       block_input ();
+      xwidget_view_delete_all_in_window (w);
       window_resize_apply (p, horflag);
       /* If this window is referred to by the dpyinfo's mouse
         highlight, invalidate that slot to be safe (Bug#9904).  */
@@ -4711,6 +4529,7 @@ grow_mini_window (struct window *w, int delta, bool pixelwise)
          /* Enforce full redisplay of the frame.  */
          /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
          fset_redisplay (f);
+         FRAME_WINDOW_SIZES_CHANGED (f) = true;
          adjust_frame_glyphs (f);
          unblock_input ();
        }
@@ -4750,6 +4569,7 @@ shrink_mini_window (struct window *w, bool pixelwise)
          /* Enforce full redisplay of the frame.  */
          /* FIXME: Shouldn't window--resize-root-window-vertically do it?  */
          fset_redisplay (f);
+         FRAME_WINDOW_SIZES_CHANGED (f) = true;
          adjust_frame_glyphs (f);
          unblock_input ();
        }
@@ -4993,7 +4813,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
                  set_marker_restricted (w->start, make_number (spos),
                                         w->contents);
                  w->start_at_line_beg = true;
-                 w->update_mode_line = true;
+                 wset_update_mode_line (w);
                  /* Set force_start so that redisplay_window will run the
                     window-scroll-functions.  */
                  w->force_start = true;
@@ -5141,7 +4961,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
                                  IT_BYTEPOS (it));
       bytepos = marker_byte_position (w->start);
       w->start_at_line_beg = (pos == BEGV || FETCH_BYTE (bytepos - 1) == '\n');
-      w->update_mode_line = true;
+      wset_update_mode_line (w);
       /* Set force_start so that redisplay_window will run the
         window-scroll-functions.  */
       w->force_start = true;
@@ -5163,27 +4983,34 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
 
   if (n > 0)
     {
+      int last_y = it.last_visible_y - this_scroll_margin - 1;
+
       /* We moved the window start towards ZV, so PT may be now
         in the scroll margin at the top.  */
       move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
-      if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin
+      if (IT_CHARPOS (it) == PT
+         && it.current_y >= this_scroll_margin
+         && it.current_y <= last_y - WINDOW_HEADER_LINE_HEIGHT (w)
           && (NILP (Vscroll_preserve_screen_position)
              || EQ (Vscroll_preserve_screen_position, Qt)))
        /* We found PT at a legitimate height.  Leave it alone.  */
        ;
-      else if (window_scroll_pixel_based_preserve_y >= 0)
-       {
-         /* If we have a header line, take account of it.
-            This is necessary because we set it.current_y to 0, above.  */
-         move_it_to (&it, -1,
-                     window_scroll_pixel_based_preserve_x,
-                     (window_scroll_pixel_based_preserve_y
-                      - WINDOW_WANTS_HEADER_LINE_P (w)),
-                     -1, MOVE_TO_Y | MOVE_TO_X);
-         SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
-       }
       else
        {
+         if (window_scroll_pixel_based_preserve_y >= 0)
+           {
+             /* Don't enter the scroll margin at the end of the window.  */
+             int goal_y = min (last_y, window_scroll_pixel_based_preserve_y);
+
+             /* If we have a header line, take account of it.  This
+                is necessary because we set it.current_y to 0, above.  */
+             move_it_to (&it, -1,
+                         window_scroll_pixel_based_preserve_x,
+                         goal_y - WINDOW_HEADER_LINE_HEIGHT (w),
+                         -1, MOVE_TO_Y | MOVE_TO_X);
+           }
+
+         /* Get out of the scroll margin at the top of the window.  */
          while (it.current_y < this_scroll_margin)
            {
              int prev = it.current_y;
@@ -5207,7 +5034,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
       /* We moved the window start towards BEGV, so PT may be now
         in the scroll margin at the bottom.  */
       move_it_to (&it, PT, -1,
-                 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w)
+                 (it.last_visible_y - WINDOW_HEADER_LINE_HEIGHT (w)
                   - this_scroll_margin - 1),
                  -1,
                  MOVE_TO_POS | MOVE_TO_Y);
@@ -5258,14 +5085,20 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
        ;
       else if (window_scroll_pixel_based_preserve_y >= 0)
        {
+         int goal_y = min (it.last_visible_y - this_scroll_margin - 1,
+                           window_scroll_pixel_based_preserve_y);
+
+         /* Don't let the preserved screen Y coordinate put us inside
+            any of the two margins.  */
+         if (goal_y < this_scroll_margin)
+           goal_y = this_scroll_margin;
          SET_TEXT_POS_FROM_MARKER (start, w->start);
          start_display (&it, w, start);
          /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
             here because we called start_display again and did not
             alter it.current_y this time.  */
          move_it_to (&it, -1, window_scroll_pixel_based_preserve_x,
-                     window_scroll_pixel_based_preserve_y, -1,
-                     MOVE_TO_Y | MOVE_TO_X);
+                     goal_y, -1, MOVE_TO_Y | MOVE_TO_X);
          SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
        }
       else
@@ -5375,12 +5208,13 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
 
       set_marker_restricted_both (w->start, w->contents, pos, pos_byte);
       w->start_at_line_beg = !NILP (bolp);
-      w->update_mode_line = true;
+      wset_update_mode_line (w);
       /* Set force_start so that redisplay_window will run
         the window-scroll-functions.  */
       w->force_start = true;
 
       if (!NILP (Vscroll_preserve_screen_position)
+         && this_scroll_margin == 0
          && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
        {
          SET_PT_BOTH (pos, pos_byte);
@@ -5406,8 +5240,16 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
                         marker_byte_position (opoint_marker));
          else if (!NILP (Vscroll_preserve_screen_position))
            {
+             int nlines = window_scroll_preserve_vpos;
+
              SET_PT_BOTH (pos, pos_byte);
-             Fvertical_motion (original_pos, window, Qnil);
+             if (window_scroll_preserve_vpos < this_scroll_margin)
+               nlines = this_scroll_margin;
+             else if (window_scroll_preserve_vpos
+                      >= w->total_lines - this_scroll_margin)
+               nlines = w->total_lines - this_scroll_margin - 1;
+             Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos),
+                                      make_number (nlines)), window, Qnil);
            }
          else
            SET_PT (top_margin);
@@ -5433,8 +5275,16 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
            {
              if (!NILP (Vscroll_preserve_screen_position))
                {
+                 int nlines = window_scroll_preserve_vpos;
+
                  SET_PT_BOTH (pos, pos_byte);
-                 Fvertical_motion (original_pos, window, Qnil);
+                 if (window_scroll_preserve_vpos < this_scroll_margin)
+                   nlines = this_scroll_margin;
+                 else if (window_scroll_preserve_vpos
+                          >= ht - this_scroll_margin)
+                   nlines = ht - this_scroll_margin - 1;
+                 Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos),
+                                          make_number (nlines)), window, Qnil);
                }
              else
                Fvertical_motion (make_number (-1), window, Qnil);
@@ -6782,7 +6632,6 @@ apply_window_adjustment (struct window *w)
   eassert (w);
   clear_glyph_matrix (w->current_matrix);
   w->window_end_valid = false;
-  windows_or_buffers_changed = 30;
   wset_redisplay (w);
   adjust_frame_glyphs (XFRAME (WINDOW_FRAME (w)));
 }
@@ -7414,7 +7263,7 @@ resizing a window preferably resizes one adjacent window only.
 
 If this variable is t, splitting a window tries to get the space
 proportionally from all windows in the same combination.  This also
-allows to split a window that is otherwise too small or of fixed size.
+allows splitting a window that is otherwise too small or of fixed size.
 Resizing and deleting a window proportionally resize all windows in the
 same combination.
 
@@ -7548,18 +7397,12 @@ displayed after a scrolling operation to be somewhat inaccurate.  */);
   defsubr (&Sset_window_hscroll);
   defsubr (&Swindow_redisplay_end_trigger);
   defsubr (&Sset_window_redisplay_end_trigger);
-  defsubr (&Swindow_edges);
-  defsubr (&Swindow_pixel_edges);
-  defsubr (&Swindow_absolute_pixel_edges);
   defsubr (&Swindow_mode_line_height);
   defsubr (&Swindow_header_line_height);
   defsubr (&Swindow_right_divider_width);
   defsubr (&Swindow_bottom_divider_width);
   defsubr (&Swindow_scroll_bar_width);
   defsubr (&Swindow_scroll_bar_height);
-  defsubr (&Swindow_inside_edges);
-  defsubr (&Swindow_inside_pixel_edges);
-  defsubr (&Swindow_inside_absolute_pixel_edges);
   defsubr (&Scoordinates_in_window_p);
   defsubr (&Swindow_at);
   defsubr (&Swindow_point);