emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] scratch/follow e8937de: Replace GROUP argument in six wind


From: Alan Mackenzie
Subject: [Emacs-diffs] scratch/follow e8937de: Replace GROUP argument in six window primitives by new functions.
Date: Mon, 14 Dec 2015 16:52:52 +0000

branch: scratch/follow
commit e8937de5547a687b6d03199368645f168cb8ad37
Author: Alan Mackenzie <address@hidden>
Commit: Alan Mackenzie <address@hidden>

    Replace GROUP argument in six window primitives by new functions.
    
    * doc/lispref/windows.texi (Window Start and End, Textual Scrolling)
    * doc/lispref/positions.texi (Screen Lines): Remove optional GROUP argument
    from description of six window functions.  Add in description of new 
functions
    window-group-start, window-group-end, set-window-group-start,
    pos-visible-in-window-group-p, recenter-group and move-to-window-group-line,
    together with the six variables indirecting to the pertinent group
    functions.
    
    * src/window.c
    * src/keyboard.c: Revert the commit from 2015-11-11 12:02:48, in so far as 
it
    applies to these two files, which added the GROUP argument to six window
    primitives.
    
    * lisp/follow.el (follow-mode): Use updated variable names for the 
indirected
    functions.
    
    * lisp/isearch.el (isearch-update, isearch-done, 
isearch-string-out-of-window)
    (isearch-back-into-window, isearch-lazy-highlight-new-loop)
    (isearch-lazy-highlight-search, isearch-lazy-highlight-update): Replace 
calls
    to window primitives (e.g. window-start) with a GROUP argument by calls to
    new functions (e.g. window-group-start).
    
    * lisp/ispell.el (ispell-command-loop): Replace call to
    pos-visible-in-window-p with pos-visible-in-window-group-p.
    
    * lisp/window.el (window-group-start, window-group-end)
    (set-window-group-start, recenter-group, pos-visible-in-window-group-p)
    (selected-window-group, move-to-window-group-line): New functions.
    (window-group-start-function, window-group-end-function)
    (set-window-group-start-function, recenter-group-function)
    (pos-visible-in-window-group-p-function, selected-window-group-function)
    (move-to-window-group-line-function): New variables.
---
 doc/lispref/positions.texi |   26 +-
 doc/lispref/windows.texi   |  116 ++++---
 lisp/follow.el             |   20 +-
 lisp/isearch.el            |   54 ++--
 lisp/textmodes/ispell.el   |    2 +-
 lisp/window.el             |  157 +++++++++-
 src/keyboard.c             |    2 +-
 src/window.c               |  772 ++++++++++++++++++--------------------------
 8 files changed, 572 insertions(+), 577 deletions(-)

diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index e0496e3..090eb45 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -551,8 +551,7 @@ current buffer, regardless of which buffer is displayed in
 any buffer, whether or not it is currently displayed in some window.
 @end defun
 
address@hidden Command move-to-window-line count group
address@hidden move-to-window-line-group-function
address@hidden Command move-to-window-line count
 This function moves point with respect to the text currently displayed
 in the selected window.  It moves point to the beginning of the screen
 line @var{count} screen lines from the top of the window.  If
@@ -571,18 +570,21 @@ In an interactive call, @var{count} is the numeric prefix 
argument.
 
 The value returned is the window line number point has moved to, with
 the top line in the window numbered 0.
-
-If @var{group} is address@hidden, and the selected window is a part of
-a group of windows (@pxref{Basic Windows}), @code{move-to-window-line}
-will move to a position with respect to the entire group, not just the
-single window.  This condition holds when the buffer local variable
address@hidden is set to a function.  In
-this case, @code{move-to-window-line} calls the function with the
-argument @var{count}, then returns its result, instead of performing
-the actions described above.  Typically, the function will call
address@hidden recursively.
 @end deffn
 
address@hidden move-to-window-group-line-function
address@hidden move-to-window-group-line count
+This function is like @code{move-to-window-line}, except that when the
+selected window is a part of a group of windows (@pxref{Basic
+Windows}), @code{move-to-window-group-line} will move to a position
+with respect to the entire group, not just the single window.  This
+condition holds when the buffer local variable
address@hidden is set to a function.  In
+this case, @code{move-to-window-group-line} calls the function with
+the argument @var{count}, then returns its result.  The argument has
+the same meaning as in @code{move-to-window-line}.
address@hidden defun
+
 @defun compute-motion from frompos to topos width offsets window
 This function scans the current buffer, calculating screen positions.
 It scans the buffer forward from position @var{from}, assuming that is
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index f92289f..4589958 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -3104,8 +3104,7 @@ using the commands of Lisp mode, because they trigger this
 readjustment.  To test such code, put it into a command and bind the
 command to a key.
 
address@hidden window-start &optional window group
address@hidden window-start-group-function
address@hidden window-start &optional window
 @cindex window top line
 This function returns the display-start position of window
 @var{window}.  If @var{window} is @code{nil}, the selected window is
@@ -3121,20 +3120,22 @@ it explicitly since the previous redisplay)---to make 
sure point appears
 on the screen.  Nothing except redisplay automatically changes the
 window-start position; if you move point, do not expect the window-start
 position to change in response until after the next redisplay.
address@hidden defun
 
-If @var{group} is address@hidden, and @var{window} is a part of a
-group of windows (@pxref{Basic Windows}), @code{window-start} returns
-the start position of the entire group.  This condition holds when the
-buffer local variable @code{window-start-group-function} is set to a
-function.  In this case, @code{window-start} calls the function with
-the single argument @var{window}, then returns its result, instead of
-performing the actions described above.  Typically, the function will
-call @code{window-start} recursively.
address@hidden window-group-start &optional window
address@hidden window-group-start-function
+This function is like @code{window-start}, except that when
address@hidden is a part of a group of windows (@pxref{Basic Windows}),
address@hidden returns the start position of the entire
+group.  This condition holds when the buffer local variable
address@hidden is set to a function.  In this
+case, @code{window-group-start} calls the function with the single
+argument @var{window}, then returns its result.  The argument to this
+function has the same meaning as in @code{window-start}.
 @end defun
 
address@hidden window-end-group-function
 @cindex window end position
address@hidden window-end &optional window update group
address@hidden window-end &optional window update
 This function returns the position where display of its buffer ends in
 @var{window}.  The default for @var{window} is the selected window.
 
@@ -3157,19 +3158,21 @@ attempt to scroll the display if point has moved off 
the screen, the
 way real redisplay would do.  It does not alter the
 @code{window-start} value.  In effect, it reports where the displayed
 text will end if scrolling is not required.
address@hidden defun
 
-If @var{group} is address@hidden, and @var{window} is a part of a
-group of windows (@pxref{Basic Windows}), `window-end' returns the end
-position of the entire group.  This condition holds when the buffer
-local variable @code{window-end-group-function} is set to a function.
-In this case, @code{window-end} calls the function with the two
-arguments @var{window} and @var{update}, then returns its result,
-instead of performing the actions described above.  Typically, the
-function will call @code{window-end} recursively.
address@hidden window-group-end-function
address@hidden window-group-end window update
+This function is like @code{window-end}, except that when @var{window}
+is a part of a group of windows (@pxref{Basic Windows}),
address@hidden returns the end position of the entire group.
+This condition holds when the buffer local variable
address@hidden is set to a function.  In this case,
address@hidden calls the function with the two arguments
address@hidden and @var{update}, then returns its result.  The arguments
+to this function have the same meaning as in @code{window-end}.
 @end defun
 
address@hidden set-window-start-group-function
address@hidden set-window-start window position &optional noforce group
address@hidden set-window-start window position &optional noforce
 This function sets the display-start position of @var{window} to
 @var{position} in @var{window}'s buffer.  It returns @var{position}.
 
@@ -3230,20 +3233,22 @@ it is still 1 when redisplay occurs.  Here is an 
example:
 If @var{noforce} is address@hidden, and @var{position} would place point
 off screen at the next redisplay, then redisplay computes a new window-start
 position that works well with point, and thus @var{position} is not used.
address@hidden defun
 
-If @var{group} is address@hidden, and @var{window} is a part of a
-group of windows (@pxref{Basic Windows}), @code{set-window-start} sets
-the start position of the entire group.  This condition holds when the
-buffer local variable @code{set-window-start-group-function} is set to
-a function.  In this case, @code{set-window-start} calls the function
-with the three arguments @var{window}, @var{position}, and
address@hidden, then returns its result, instead of performing the
-actions described above.  Typically, the function will call
address@hidden recursively.
address@hidden set-window-group-start-function
address@hidden set-window-group-start window position &optional noforce
+This function is like @code{set-window-start}, except that when
address@hidden is a part of a group of windows (@pxref{Basic Windows}),
address@hidden sets the start position of the entire
+group.  This condition holds when the buffer local variable
address@hidden is set to a function.  In this
+case, @code{set-window-group-start} calls the function with the three
+arguments @var{window}, @var{position}, and @var{noforce}, then
+returns its result.  The arguments in this function have the same
+meaning as in @code{set-window-start}.
 @end defun
 
address@hidden pos-visible-in-window-p &optional position window partially group
address@hidden pos-visible-in-window-p-group-function
address@hidden pos-visible-in-window-p &optional position window partially
 This function returns address@hidden if @var{position} is within the
 range of text currently visible on the screen in @var{window}.  It
 returns @code{nil} if @var{position} is scrolled vertically out of
@@ -3282,18 +3287,19 @@ Here is an example:
     (recenter 0))
 @end group
 @end example
address@hidden defun
 
-If @var{group} is address@hidden, and @var{window} is a part of a
-group of windows (@pxref{Basic Windows}),
address@hidden tests the visibility of @var{pos} in
-the entire group, not just in the single @var{window}.  This condition
-holds when the buffer local variable
address@hidden is set to a function.
-In this case @code{pos-visible-in-window-p} calls the function with
-the three arguments @var{position}, @var{window}, and @var{partially},
-then returns its result, instead of performing the actions described
-above.  Typically, the function will call
address@hidden recursively.
address@hidden pos-visible-in-window-group-p-function
address@hidden pos-visible-in-window-group-p &optional position window partially
+This function is like @code{pos-visible-in-window-p}, except that when
address@hidden is a part of a group of windows (@pxref{Basic Windows}),
address@hidden tests the visibility of @var{pos}
+in the entire group, not just in the single @var{window}.  This
+condition holds when the buffer local variable
address@hidden is set to a function.
+In this case @code{pos-visible-in-window-group-p} calls the function
+with the three arguments @var{position}, @var{window}, and
address@hidden, then returns its result.
 @end defun
 
 @defun window-line-height &optional line window
@@ -3511,8 +3517,7 @@ beginning or end of the buffer (depending on scrolling 
direction);
 only if point is already on that position do they signal an error.
 @end defopt
 
address@hidden Command recenter &optional count group
address@hidden recenter-group-function
address@hidden Command recenter &optional count
 @cindex centering point
 This function scrolls the text in the selected window so that point is
 displayed at a specified vertical position within the window.  It does
@@ -3529,14 +3534,6 @@ If @var{count} is @code{nil} (or a address@hidden list),
 window.  If @var{count} is @code{nil}, this function may redraw the
 frame, according to the value of @code{recenter-redisplay}.
 
-If @var{group} is address@hidden, and the selected window is part of a
-group of windows (@pxref{Basic Windows}), @code{recenter} scrolls the
-entire group.  This condition holds when the buffer local variable
address@hidden is set to a function.  In this case,
address@hidden calls the function with the argument @var{count}, then
-returns its result, instead of performing the actions described above.
-Typically, the function will call @code{recenter} recursively.
-
 When @code{recenter} is called interactively, @var{count} is the raw
 prefix argument.  Thus, typing @kbd{C-u} as the prefix sets the
 @var{count} to a address@hidden list, while typing @kbd{C-u 4} sets
@@ -3548,6 +3545,17 @@ the top of the window.  The command 
@code{recenter-top-bottom} offers
 a more convenient way to achieve this.
 @end deffn
 
address@hidden recenter-group-function
address@hidden recenter-group &optional count
+This function is like @code{recenter}, except that when the selected
+window is part of a group of windows (@pxref{Basic Windows}),
address@hidden scrolls the entire group.  This condition holds
+when the buffer local variable @code{recenter-group-function} is set
+to a function.  In this case, @code{recenter-group} calls the function
+with the argument @var{count}, then returns its result.  The argument
+has the same meaning as in @code{recenter}.
address@hidden defun
+
 @defopt recenter-redisplay
 If this variable is address@hidden, calling @code{recenter} with a
 @code{nil} argument redraws the frame.  The default value is
diff --git a/lisp/follow.el b/lisp/follow.el
index 609b29f..3a876bc 100644
--- a/lisp/follow.el
+++ b/lisp/follow.el
@@ -427,14 +427,14 @@ Keys specific to Follow mode:
         (add-hook 'replace-update-post-hook 'follow-post-command-hook nil t)
         (add-hook 'ispell-update-post-hook 'follow-post-command-hook nil t)
 
-        (setq window-start-group-function 'follow-window-start)
-        (setq window-end-group-function 'follow-window-end)
-        (setq set-window-start-group-function 'follow-set-window-start)
+        (setq window-group-start-function 'follow-window-start)
+        (setq window-group-end-function 'follow-window-end)
+        (setq set-window-group-start-function 'follow-set-window-start)
         (setq recenter-group-function 'follow-recenter)
-        (setq pos-visible-in-window-p-group-function
+        (setq pos-visible-in-window-group-p-function
               'follow-pos-visible-in-window-p)
         (setq selected-window-group-function 'follow-all-followers)
-        (setq move-to-window-line-group-function 'follow-move-to-window-line))
+        (setq move-to-window-group-line-function 'follow-move-to-window-line))
 
     ;; Remove globally-installed hook functions only if there is no
     ;; other Follow mode buffer.
@@ -447,13 +447,13 @@ Keys specific to Follow mode:
        (remove-hook 'post-command-hook 'follow-post-command-hook)
        (remove-hook 'window-size-change-functions 'follow-window-size-change)))
 
-    (kill-local-variable 'move-to-window-line-group-function)
+    (kill-local-variable 'move-to-window-group-line-function)
     (kill-local-variable 'selected-window-group-function)
-    (kill-local-variable 'pos-visible-in-window-p-group-function)
+    (kill-local-variable 'pos-visible-in-window-group-p-function)
     (kill-local-variable 'recenter-group-function)
-    (kill-local-variable 'set-window-start-group-function)
-    (kill-local-variable 'window-end-group-function)
-    (kill-local-variable 'window-start-group-function)
+    (kill-local-variable 'set-window-group-start-function)
+    (kill-local-variable 'window-group-end-function)
+    (kill-local-variable 'window-group-start-function)
 
     (remove-hook 'ispell-update-post-hook 'follow-post-command-hook t)
     (remove-hook 'replace-update-post-hook 'follow-post-command-hook t)
diff --git a/lisp/isearch.el b/lisp/isearch.el
index 8e9a686..b29e432 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -982,7 +982,7 @@ The last thing is to trigger a new round of lazy 
highlighting."
           (funcall (or isearch-message-function #'isearch-message)))
         (if (and isearch-slow-terminal-mode
                  (not (or isearch-small-window
-                          (pos-visible-in-window-p nil nil nil t))))
+                          (pos-visible-in-window-group-p))))
             (let ((found-point (point)))
               (setq isearch-small-window t)
               (move-to-window-line 0)
@@ -1003,10 +1003,10 @@ The last thing is to trigger a new round of lazy 
highlighting."
          (let ((current-scroll (window-hscroll))
                visible-p)
            (set-window-hscroll (selected-window) isearch-start-hscroll)
-           (setq visible-p (pos-visible-in-window-p nil nil t t))
+           (setq visible-p (pos-visible-in-window-group-p nil nil t))
            (if (or (not visible-p)
                    ;; When point is not visible because of hscroll,
-                   ;; pos-visible-in-window-p returns non-nil, but
+                   ;; pos-visible-in-window-group-p returns non-nil, but
                    ;; the X coordinate it returns is 1 pixel beyond
                    ;; the last visible one.
                    (>= (car visible-p) (window-body-width nil t)))
@@ -1057,7 +1057,7 @@ NOPUSH is t and EDIT is t."
   (setq minibuffer-message-timeout isearch-original-minibuffer-message-timeout)
   (isearch-dehighlight)
   (lazy-highlight-cleanup lazy-highlight-cleanup)
-  (let ((found-start (window-start nil t))
+  (let ((found-start (window-group-start))
        (found-point (point)))
     (when isearch-window-configuration
       (set-window-configuration isearch-window-configuration)
@@ -1067,7 +1067,7 @@ NOPUSH is t and EDIT is t."
        ;; This has an annoying side effect of clearing the last_modiff
        ;; field of the window, which can cause unwanted scrolling,
        ;; so don't do it unless truly necessary.
-       (set-window-start (selected-window) found-start t t))))
+       (set-window-group-start (selected-window) found-start t))))
 
   (setq isearch-mode nil)
   (if isearch-input-method-local-p
@@ -2279,12 +2279,12 @@ Return nil if it's completely visible, or if point is 
visible,
 together with as much of the search string as will fit; the symbol
 `above' if we need to scroll the text downwards; the symbol `below',
 if upwards."
-  (let ((w-start (window-start nil t))
-        (w-end (window-end nil t t))
+  (let ((w-start (window-group-start))
+        (w-end (window-group-end nil t))
         (w-L1 (save-excursion
-                (save-selected-window (move-to-window-line 1 t) (point))))
+                (save-selected-window (move-to-window-group-line 1) (point))))
         (w-L-1 (save-excursion
-                 (save-selected-window (move-to-window-line -1 t) (point))))
+                 (save-selected-window (move-to-window-group-line -1) 
(point))))
         start end)                  ; start and end of search string in buffer
     (if isearch-forward
         (setq end isearch-point  start (or isearch-other-end isearch-point))
@@ -2311,15 +2311,15 @@ the bottom."
     (if above
         (progn
           (goto-char start)
-          (recenter 0 t)
-          (when (>= isearch-point (window-end nil t t))
+          (recenter-group 0)
+          (when (>= isearch-point (window-group-end nil t))
             (goto-char isearch-point)
-            (recenter -1 t)))
+            (recenter-group -1)))
       (goto-char end)
-      (recenter -1 t)
-      (when (< isearch-point (window-start nil t))
+      (recenter-group -1)
+      (when (< isearch-point (window-group-start))
         (goto-char isearch-point)
-        (recenter 0 t))))
+        (recenter-group 0))))
   (goto-char isearch-point))
 
 (defvar isearch-pre-scroll-point nil)
@@ -3090,9 +3090,9 @@ by other Emacs features."
                          isearch-lax-whitespace))
                 (not (eq isearch-lazy-highlight-regexp-lax-whitespace
                          isearch-regexp-lax-whitespace))
-                 (not (= (window-start nil t)
+                 (not (= (window-group-start)
                          isearch-lazy-highlight-window-start))
-                 (not (= (window-end nil nil t) ; Window may have been 
split/joined.
+                 (not (= (window-group-end) ; Window may have been 
split/joined.
                         isearch-lazy-highlight-window-end))
                 (not (eq isearch-forward
                          isearch-lazy-highlight-forward))
@@ -3109,8 +3109,8 @@ by other Emacs features."
          isearch-lazy-highlight-end-limit end)
     (setq isearch-lazy-highlight-window       (selected-window)
           isearch-lazy-highlight-window-group (selected-window-group)
-         isearch-lazy-highlight-window-start (window-start nil t)
-         isearch-lazy-highlight-window-end   (window-end nil nil t)
+         isearch-lazy-highlight-window-start (window-group-start)
+         isearch-lazy-highlight-window-end   (window-group-end)
          ;; Start lazy-highlighting at the beginning of the found
          ;; match (`isearch-other-end').  If no match, use point.
          ;; One of the next two variables (depending on search direction)
@@ -3154,13 +3154,13 @@ Attempt to do the search exactly the way the pending 
Isearch would."
                                (+ isearch-lazy-highlight-start
                                   ;; Extend bound to match whole string at 
point
                                   (1- (length 
isearch-lazy-highlight-last-string)))
-                             (window-end nil nil t)))
+                             (window-group-end)))
                     (max (or isearch-lazy-highlight-start-limit (point-min))
                          (if isearch-lazy-highlight-wrapped
                              (- isearch-lazy-highlight-end
                                 ;; Extend bound to match whole string at point
                                 (1- (length 
isearch-lazy-highlight-last-string)))
-                           (window-start nil t))))))
+                           (window-group-start))))))
        ;; Use a loop like in `isearch-search'.
        (while retry
          (setq success (isearch-search-string
@@ -3204,12 +3204,12 @@ Attempt to do the search exactly the way the pending 
Isearch would."
                          (if isearch-lazy-highlight-forward
                              (if (= mb (if isearch-lazy-highlight-wrapped
                                            isearch-lazy-highlight-start
-                                         (window-end nil nil t)))
+                                         (window-group-end)))
                                  (setq found nil)
                                (forward-char 1))
                            (if (= mb (if isearch-lazy-highlight-wrapped
                                          isearch-lazy-highlight-end
-                                       (window-start nil t)))
+                                       (window-group-start)))
                                (setq found nil)
                              (forward-char -1)))
 
@@ -3236,12 +3236,12 @@ Attempt to do the search exactly the way the pending 
Isearch would."
                      (setq isearch-lazy-highlight-wrapped t)
                      (if isearch-lazy-highlight-forward
                          (progn
-                           (setq isearch-lazy-highlight-end (window-start nil 
t))
+                           (setq isearch-lazy-highlight-end 
(window-group-start))
                            (goto-char (max (or 
isearch-lazy-highlight-start-limit (point-min))
-                                           (window-start nil t))))
-                       (setq isearch-lazy-highlight-start (window-end nil nil 
t))
+                                           (window-group-start))))
+                       (setq isearch-lazy-highlight-start (window-group-end))
                        (goto-char (min (or isearch-lazy-highlight-end-limit 
(point-max))
-                                       (window-end nil nil t))))))))
+                                       (window-group-end))))))))
            (unless nomore
              (setq isearch-lazy-highlight-timer
                    (run-at-time lazy-highlight-interval nil
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 7d5bb6d..0f1806c 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -2323,7 +2323,7 @@ Global `ispell-quit' set to start location to continue 
spell session."
     (run-hooks 'ispell-update-post-hook)
 
     ;; ensure word is visible
-    (if (not (pos-visible-in-window-p end nil nil t))
+    (if (not (pos-visible-in-window-group-p end))
        (sit-for 0))
 
     ;; Display choices for misspelled word.
diff --git a/lisp/window.el b/lisp/window.el
index c5a1019..ce0256f 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -28,17 +28,6 @@
 
 ;;; Code:
 
-(defvar selected-window-group-function nil)
-(make-variable-buffer-local 'selected-window-group-function)
-(put 'selected-window-group-function 'permanent-local t)
-(defun selected-window-group ()
-  "Return the list of windows in the group containing the selected window.
-When a grouping mode (such as Follow Mode) is not active, the
-result is a list containing only the selected window."
-  (if (functionp selected-window-group-function)
-      (funcall selected-window-group-function)
-    (list (selected-window))))
-
 (defun internal--before-save-selected-window ()
   (cons (selected-window)
         ;; We save and restore all frames' selected windows, because
@@ -7881,6 +7870,152 @@ Return non-nil if the window was shrunk, nil otherwise."
         (remove-hook 'kill-buffer-hook delete-window-hook t))))))
 
 
+;;;
+;; Groups of windows (Follow Mode).
+;;
+;; This section of functions extends the functionality of some window
+;; manipulating commands to groups of windows co-operatively
+;; displaying a buffer, typically with Follow Mode.
+;;
+;; The xxx-function variables are permanent locals so that their local
+;; status is undone only when explicitly programmed, not when a buffer
+;; is reverted or a mode function is called.
+
+(defvar window-group-start-function nil)
+(make-variable-buffer-local 'window-group-start-function)
+(put 'window-group-start-function 'permanent-local t)
+(defun window-group-start (&optional window)
+  "Return position at which display currently starts in the group of
+windows containing WINDOW.  When a grouping mode (such as Follow Mode)
+is not active, this function is identical to `window-start'.
+
+WINDOW must be a live window and defaults to the selected one.
+This is updated by redisplay or by calling `set-window*-start'."
+  (if (functionp window-group-start-function)
+      (funcall window-group-start-function window)
+    (window-start window)))
+
+(defvar window-group-end-function nil)
+(make-variable-buffer-local 'window-group-end-function)
+(put 'window-group-end-function 'permanent-local t)
+(defun window-group-end (&optional window update)
+  "Return position at which display currently ends in the group of
+windows containing WINDOW.  When a grouping mode (such as Follow Mode)
+is not active, this function is identical to `window-end'.
+
+WINDOW must be a live window and defaults to the selected one.
+This is updated by redisplay, when it runs to completion.
+Simply changing the buffer text or setting `window-group-start'
+does not update this value.
+Return nil if there is no recorded value.  (This can happen if the
+last redisplay of WINDOW was preempted, and did not finish.)
+If UPDATE is non-nil, compute the up-to-date position
+if it isn't already recorded."
+  (if (functionp window-group-end-function)
+      (funcall window-group-end-function window update)
+    (window-end window update)))
+
+(defvar set-window-group-start-function nil)
+(make-variable-buffer-local 'set-window-group-start-function)
+(put 'set-window-group-start-function 'permanent-local t)
+(defun set-window-group-start (window pos &optional noforce)
+  "Make display in the group of windows containing WINDOW start at
+position POS in WINDOW's buffer.  When a grouping mode (such as Follow
+Mode) is not active, this function is identical to `set-window-start'.
+
+WINDOW must be a live window and defaults to the selected one.  Return
+POS.  Optional third arg NOFORCE non-nil inhibits next redisplay from
+overriding motion of point in order to display at this exact start."
+  (if (functionp set-window-group-start-function)
+      (funcall set-window-group-start-function window pos noforce)
+    (set-window-start window pos noforce)))
+
+(defvar recenter-group-function nil)
+(make-variable-buffer-local 'recenter-group-function)
+(put 'recenter-group-function 'permanent-local t)
+(defun recenter-group (&optional arg)
+  "Center point in the group of windows containing the selected window
+and maybe redisplay frame.  When a grouping mode (such as Follow Mode)
+is not active, this function is identical to `recenter'.
+
+With a numeric prefix argument ARG, recenter putting point on screen line ARG
+relative to the first window in the selected window group.  If ARG is
+negative, it counts up from the bottom of the last window in the
+group.  (ARG should be less than the total height of the window group.)
+
+If ARG is omitted or nil, then recenter with point on the middle line of
+the selected window group; if the variable `recenter-redisplay' is
+non-nil, also erase the entire frame and redraw it (when
+`auto-resize-tool-bars' is set to `grow-only', this resets the
+tool-bar's height to the minimum height needed); if
+`recenter-redisplay' has the special value `tty', then only tty frames
+are redrawn.
+
+Just C-u as prefix means put point in the center of the window
+and redisplay normally--don't erase and redraw the frame."
+  (if (functionp recenter-group-function)
+      (funcall recenter-group-function arg)
+    (recenter arg)))
+
+(defvar pos-visible-in-window-group-p-function nil)
+(make-variable-buffer-local 'pos-visible-in-window-group-p-function)
+(put 'pos-visible-in-window-group-p-function 'permanent-local t)
+(defun pos-visible-in-window-group-p (&optional pos window partially)
+  "Return non-nil if position POS is currently on the frame in the
+window group containing WINDOW.  When a grouping mode (such as Follow
+Mode) is not active, this function is identical to
+`pos-visible-in-window-p'.
+
+WINDOW must be a live window and defaults to the selected one.
+
+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 the window group.
+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]),
+where X and Y are the pixel coordinates relative to the top left corner
+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)."
+  (if (functionp pos-visible-in-window-group-p-function)
+      (funcall pos-visible-in-window-group-p-function pos window partially)
+    (pos-visible-in-window-p pos window partially)))
+
+(defvar selected-window-group-function nil)
+(make-variable-buffer-local 'selected-window-group-function)
+(put 'selected-window-group-function 'permanent-local t)
+(defun selected-window-group ()
+  "Return the list of windows in the group containing the selected window.
+When a grouping mode (such as Follow Mode) is not active, the
+result is a list containing only the selected window."
+  (if (functionp selected-window-group-function)
+      (funcall selected-window-group-function)
+    (list (selected-window))))
+
+(defvar move-to-window-group-line-function nil)
+(make-variable-buffer-local 'move-to-window-group-line-function)
+(put 'move-to-window-group-line-function 'permanent-local t)
+(defun move-to-window-group-line (arg)
+  "Position point relative to the the current group of windows.
+When a grouping mode (such as Follow Mode) is not active, this
+function is identical to `move-to-window-line'.
+
+ARG nil means position point at center of the window group.
+Else, ARG specifies the vertical position within the window
+group; zero means top of first window in the group, negative
+means relative to the bottom of the last window in the group."
+  (if (functionp move-to-window-group-line-function)
+      (funcall move-to-window-group-line-function arg)
+    (move-to-window-line arg)))
+
+
 (defvar recenter-last-op nil
   "Indicates the last recenter operation performed.
 Possible values: `top', `middle', `bottom', integer or float numbers.
diff --git a/src/keyboard.c b/src/keyboard.c
index 725c324..02bc7d2 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -10658,7 +10658,7 @@ The `posn-' functions access elements of such lists.  
*/)
   if (NILP (window))
     window = selected_window;
 
-  tem = Fpos_visible_in_window_p (pos, window, Qt, Qnil);
+  tem = Fpos_visible_in_window_p (pos, window, Qt);
   if (!NILP (tem))
     {
       Lisp_Object x = XCAR (tem);
diff --git a/src/window.c b/src/window.c
index 1a0163c..9f6b489 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1540,23 +1540,13 @@ WINDOW must be a live window and defaults to the 
selected one.  */)
   return Fmarker_position (decode_live_window (window)->old_pointm);
 }
 
-DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 2, 0,
+DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0,
        doc: /* Return position at which display currently starts in WINDOW.
 WINDOW must be a live window and defaults to the selected one.
-This is updated by redisplay or by calling `set-window-start'.
-
-If GROUP is non-nil, and WINDOW is part of a group of windows collectively
-displaying a buffer (such as with Follow Mode), return the start position of
-the group rather than of the individual WINDOW.  This condition holds when
-`window-start-group-function' is set to a function, in which case
-`window-start' calls the function with the argument WINDOW, then returns its
-result, instead of doing its normal processing.  */)
-  (Lisp_Object window, Lisp_Object group)
+This is updated by redisplay or by calling `set-window-start'.  */)
+  (Lisp_Object window)
 {
-  return (!NILP (group)
-          && FUNCTIONP (Vwindow_start_group_function))
-    ? call1 (Vwindow_start_group_function, window)
-    : Fmarker_position (decode_live_window (window)->start);
+  return Fmarker_position (decode_live_window (window)->start);
 }
 
 /* This is text temporarily removed from the doc string below.
@@ -1570,7 +1560,7 @@ have been if redisplay had finished, do this:
       (vertical-motion (1- (window-height window)) window)
       (point))")  */
 
-DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 3, 0,
+DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0,
        doc: /* Return position at which display currently ends in WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 This is updated by redisplay, when it runs to completion.
@@ -1579,77 +1569,65 @@ does not update this value.
 Return nil if there is no recorded value.  (This can happen if the
 last redisplay of WINDOW was preempted, and did not finish.)
 If UPDATE is non-nil, compute the up-to-date position
-if it isn't already recorded.
-
-If GROUP is non-nil, and WINDOW is part of a group of windows collectively
-displaying a buffer (such as with Follow Mode), return the end position of
-the group rather than of the individual WINDOW.  This condition holds when
-`window-end-group-function' is set to a function, in which case `window-end'
-calls the function with the two arguments WINDOW and UPDATE, then returns its
-result, instead of doing its normal processing.  */)
-  (Lisp_Object window, Lisp_Object update, Lisp_Object group)
-{
-  if (!NILP (group)
-      && FUNCTIONP (Vwindow_end_group_function))
-    return call2 (Vwindow_end_group_function, window, update);
-  {
-    Lisp_Object value;
-    struct window *w = decode_live_window (window);
-    Lisp_Object buf;
-    struct buffer *b;
-
-    buf = w->contents;
-    CHECK_BUFFER (buf);
-    b = XBUFFER (buf);
-
-    if (! NILP (update)
-        && (windows_or_buffers_changed
-            || !w->window_end_valid
-            || b->clip_changed
-            || b->prevent_redisplay_optimizations_p
-            || window_outdated (w))
-        /* Don't call display routines if we didn't yet create any real
-           frames, because the glyph matrices are not yet allocated in
-           that case.  This could happen in some code that runs in the
-           daemon during initialization (e.g., see bug#20565).  */
-        && !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w))))
-      {
-        struct text_pos startp;
-        struct it it;
-        struct buffer *old_buffer = NULL;
-        void *itdata = NULL;
-
-        /* Cannot use Fvertical_motion because that function doesn't
-           cope with variable-height lines.  */
-        if (b != current_buffer)
-          {
-            old_buffer = current_buffer;
-            set_buffer_internal (b);
-          }
-
-        /* In case W->start is out of the range, use something
-           reasonable.  This situation occurred when loading a file with
-           `-l' containing a call to `rmail' with subsequent other
-           commands.  At the end, W->start happened to be BEG, while
-           rmail had already narrowed the buffer.  */
-        CLIP_TEXT_POS_FROM_MARKER (startp, w->start);
-
-        itdata = bidi_shelve_cache ();
-        start_display (&it, w, startp);
-        move_it_vertically (&it, window_box_height (w));
-        if (it.current_y < it.last_visible_y)
-          move_it_past_eol (&it);
-        value = make_number (IT_CHARPOS (it));
-        bidi_unshelve_cache (itdata, false);
-
-        if (old_buffer)
-          set_buffer_internal (old_buffer);
-      }
-    else
-      XSETINT (value, BUF_Z (b) - w->window_end_pos);
+if it isn't already recorded.  */)
+  (Lisp_Object window, Lisp_Object update)
+{
+  Lisp_Object value;
+  struct window *w = decode_live_window (window);
+  Lisp_Object buf;
+  struct buffer *b;
+
+  buf = w->contents;
+  CHECK_BUFFER (buf);
+  b = XBUFFER (buf);
+
+  if (! NILP (update)
+      && (windows_or_buffers_changed
+         || !w->window_end_valid
+         || b->clip_changed
+         || b->prevent_redisplay_optimizations_p
+         || window_outdated (w))
+      /* Don't call display routines if we didn't yet create any real
+        frames, because the glyph matrices are not yet allocated in
+        that case.  This could happen in some code that runs in the
+        daemon during initialization (e.g., see bug#20565).  */
+      && !(noninteractive || FRAME_INITIAL_P (WINDOW_XFRAME (w))))
+    {
+      struct text_pos startp;
+      struct it it;
+      struct buffer *old_buffer = NULL;
+      void *itdata = NULL;
+
+      /* Cannot use Fvertical_motion because that function doesn't
+        cope with variable-height lines.  */
+      if (b != current_buffer)
+       {
+         old_buffer = current_buffer;
+         set_buffer_internal (b);
+       }
 
-    return value;
-  }
+      /* In case W->start is out of the range, use something
+         reasonable.  This situation occurred when loading a file with
+         `-l' containing a call to `rmail' with subsequent other
+         commands.  At the end, W->start happened to be BEG, while
+         rmail had already narrowed the buffer.  */
+      CLIP_TEXT_POS_FROM_MARKER (startp, w->start);
+
+      itdata = bidi_shelve_cache ();
+      start_display (&it, w, startp);
+      move_it_vertically (&it, window_box_height (w));
+      if (it.current_y < it.last_visible_y)
+       move_it_past_eol (&it);
+      value = make_number (IT_CHARPOS (it));
+      bidi_unshelve_cache (itdata, false);
+
+      if (old_buffer)
+       set_buffer_internal (old_buffer);
+    }
+  else
+    XSETINT (value, BUF_Z (b) - w->window_end_pos);
+
+  return value;
 }
 
 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0,
@@ -1688,43 +1666,30 @@ Return POS.  */)
   return pos;
 }
 
-DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 4, 0,
+DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0,
        doc: /* Make display in WINDOW start at position POS in WINDOW's buffer.
 WINDOW must be a live window and defaults to the selected one.  Return
 POS.  Optional third arg NOFORCE non-nil inhibits next redisplay from
-overriding motion of point in order to display at this exact start.
-
-If GROUP is non-nil, and WINDOW is part of a group of windows collectively
-displaying a buffer (such as with Follow Mode), set the start position of
-the group rather than of the individual WINDOW.  This condition holds when
-`set-window-start-group-function' is set to a function, in which case
-`set-window-start' calls the function with the three arguments WINDOW, POS,
-and NOFORCE, then returns its result, instead of doing its normal
-processing.  */)
-  (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce, Lisp_Object group)
-{
-  if (!NILP (group)
-      && FUNCTIONP (Vset_window_start_group_function))
-    return call3 (Vset_window_start_group_function, window, pos, noforce);
-  {
-    register struct window *w = decode_live_window (window);
+overriding motion of point in order to display at this exact start.  */)
+  (Lisp_Object window, Lisp_Object pos, Lisp_Object noforce)
+{
+  register struct window *w = decode_live_window (window);
 
-    set_marker_restricted (w->start, pos, w->contents);
-    /* This is not right, but much easier than doing what is right.  */
-    w->start_at_line_beg = false;
-    if (NILP (noforce))
-      w->force_start = true;
-    wset_update_mode_line (w);
-    /* Bug#15957.  */
-    w->window_end_valid = false;
-    wset_redisplay (w);
+  set_marker_restricted (w->start, pos, w->contents);
+  /* This is not right, but much easier than doing what is right.  */
+  w->start_at_line_beg = false;
+  if (NILP (noforce))
+    w->force_start = true;
+  wset_update_mode_line (w);
+  /* Bug#15957.  */
+  w->window_end_valid = false;
+  wset_redisplay (w);
 
-    return pos;
-  }
+  return pos;
 }
 
 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
-       Spos_visible_in_window_p, 0, 4, 0,
+       Spos_visible_in_window_p, 0, 3, 0,
        doc: /* Return non-nil if position POS is currently on the frame in 
WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
@@ -1744,21 +1709,9 @@ 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).
-
-If GROUP is non-nil, and WINDOW is part of a group of windows collectively
-displaying a buffer (such as with Follow Mode), test whether POS is visible
-in the group of windows rather than in the individual WINDOW.  This
-condition holds when `pos-visible-in-window-p-function' is set to a
-function, in which case `pos-visible-in-window-p' calls the function with
-the three arguments POS, WINDOW, and PARTIALLY, then returns its result,
-instead of doing its normal processing.  */)
-  (Lisp_Object pos, Lisp_Object window, Lisp_Object partially, Lisp_Object 
group)
-{
-  if (!NILP (group)
-      && FUNCTIONP (Vpos_visible_in_window_p_group_function))
-    return call3 (Vpos_visible_in_window_p_group_function, pos, window, 
partially);
-  {
+(zero-based).  */)
+  (Lisp_Object pos, Lisp_Object window, Lisp_Object partially)
+{
   struct window *w;
   EMACS_INT posint;
   struct buffer *buf;
@@ -1807,7 +1760,6 @@ instead of doing its normal processing.  */)
     }
 
   return in_window;
-  }
 }
 
 DEFUN ("window-line-height", Fwindow_line_height,
@@ -5205,7 +5157,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool 
whole, bool noerror)
     }
 
   XSETFASTINT (tem, PT);
-  tem = Fpos_visible_in_window_p (tem, window, Qnil, Qnil);
+  tem = Fpos_visible_in_window_p (tem, window, Qnil);
 
   if (NILP (tem))
     {
@@ -5594,7 +5546,7 @@ displayed_window_lines (struct window *w)
 }
 
 
-DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "P\ni",
+DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P",
        doc: /* Center point in selected window and maybe redisplay frame.
 With a numeric prefix argument ARG, recenter putting point on screen line ARG
 relative to the selected window.  If ARG is negative, it counts up from the
@@ -5608,221 +5560,208 @@ height needed); if `recenter-redisplay' has the 
special value `tty',
 then only tty frames are redrawn.
 
 Just C-u as prefix means put point in the center of the window
-and redisplay normally--don't erase and redraw the frame.
-
-When `recenter' is called from a program, GROUP is non-nil, and WINDOW is
-part of a group of windows collectively displaying a buffer (such as with
-Follow Mode), perform `recenter''s actions on the group rather than on the
-individual WINDOW.  This condition holds when `recenter-group-function' is
-set to a function, in which case `recenter' calls the function with the
-argument ARG, then returns its value, instead of doing its normal
-processing.  */)
-  (register Lisp_Object arg, Lisp_Object group)
-{
-  if (!NILP (group)
-      && FUNCTIONP (Vrecenter_group_function))
-    return call1 (Vrecenter_group_function, arg);
-  {
-    struct window *w = XWINDOW (selected_window);
-    struct buffer *buf = XBUFFER (w->contents);
-    bool center_p = false;
-    ptrdiff_t charpos, bytepos;
-    EMACS_INT iarg IF_LINT (= 0);
-    int this_scroll_margin;
+and redisplay normally--don't erase and redraw the frame.  */)
+  (register Lisp_Object arg)
+{
+  struct window *w = XWINDOW (selected_window);
+  struct buffer *buf = XBUFFER (w->contents);
+  bool center_p = false;
+  ptrdiff_t charpos, bytepos;
+  EMACS_INT iarg IF_LINT (= 0);
+  int this_scroll_margin;
 
-    if (buf != current_buffer)
-      error ("`recenter'ing a window that does not display current-buffer.");
+  if (buf != current_buffer)
+    error ("`recenter'ing a window that does not display current-buffer.");
 
-    /* If redisplay is suppressed due to an error, try again.  */
-    buf->display_error_modiff = 0;
+  /* If redisplay is suppressed due to an error, try again.  */
+  buf->display_error_modiff = 0;
 
-    if (NILP (arg))
-      {
-        if (!NILP (Vrecenter_redisplay)
-            && (!EQ (Vrecenter_redisplay, Qtty)
-                || !NILP (Ftty_type (selected_frame))))
-          {
-            ptrdiff_t i;
-
-            /* Invalidate pixel data calculated for all compositions.  */
-            for (i = 0; i < n_compositions; i++)
-              composition_table[i]->font = NULL;
+  if (NILP (arg))
+    {
+      if (!NILP (Vrecenter_redisplay)
+         && (!EQ (Vrecenter_redisplay, Qtty)
+             || !NILP (Ftty_type (selected_frame))))
+       {
+         ptrdiff_t i;
+
+         /* Invalidate pixel data calculated for all compositions.  */
+         for (i = 0; i < n_compositions; i++)
+           composition_table[i]->font = NULL;
 #if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
-            WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
+         WINDOW_XFRAME (w)->minimize_tool_bar_window_p = 1;
 #endif
-            Fredraw_frame (WINDOW_FRAME (w));
-            SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
-          }
+         Fredraw_frame (WINDOW_FRAME (w));
+         SET_FRAME_GARBAGED (WINDOW_XFRAME (w));
+       }
 
-        center_p = true;
-      }
-    else if (CONSP (arg)) /* Just C-u.  */
       center_p = true;
-    else
-      {
-        arg = Fprefix_numeric_value (arg);
-        CHECK_NUMBER (arg);
-        iarg = XINT (arg);
-      }
+    }
+  else if (CONSP (arg)) /* Just C-u.  */
+    center_p = true;
+  else
+    {
+      arg = Fprefix_numeric_value (arg);
+      CHECK_NUMBER (arg);
+      iarg = XINT (arg);
+    }
 
-    /* Do this after making BUF current
-       in case scroll_margin is buffer-local.  */
-    this_scroll_margin
-      = max (0, min (scroll_margin, w->total_lines / 4));
+  /* Do this after making BUF current
+     in case scroll_margin is buffer-local.  */
+  this_scroll_margin
+    = max (0, min (scroll_margin, w->total_lines / 4));
 
-    /* Don't use redisplay code for initial frames, as the necessary
-       data structures might not be set up yet then.  */
-    if (!FRAME_INITIAL_P (XFRAME (w->frame)))
-      {
-        if (center_p)
-          {
-            struct it it;
-            struct text_pos pt;
-            void *itdata = bidi_shelve_cache ();
-
-            SET_TEXT_POS (pt, PT, PT_BYTE);
-            start_display (&it, w, pt);
-            move_it_vertically_backward (&it, window_box_height (w) / 2);
-            charpos = IT_CHARPOS (it);
-            bytepos = IT_BYTEPOS (it);
-            bidi_unshelve_cache (itdata, false);
-          }
-        else if (iarg < 0)
-          {
-            struct it it;
-            struct text_pos pt;
-            ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg);
-            int extra_line_spacing;
-            int h = window_box_height (w);
-            int ht = window_internal_height (w);
-            void *itdata = bidi_shelve_cache ();
-
-            nlines = clip_to_bounds (this_scroll_margin + 1, nlines,
-                                     ht - this_scroll_margin);
-
-            SET_TEXT_POS (pt, PT, PT_BYTE);
-            start_display (&it, w, pt);
-
-            /* Be sure we have the exact height of the full line containing 
PT.  */
-            move_it_by_lines (&it, 0);
-
-            /* The amount of pixels we have to move back is the window
-               height minus what's displayed in the line containing PT,
-               and the lines below.  */
-            it.current_y = 0;
-            it.vpos = 0;
-            move_it_by_lines (&it, nlines);
-
-            if (it.vpos == nlines)
-              h -= it.current_y;
-            else
-              {
-                /* Last line has no newline.  */
-                h -= line_bottom_y (&it);
-                it.vpos++;
-              }
-
-            /* Don't reserve space for extra line spacing of last line.  */
-            extra_line_spacing = it.max_extra_line_spacing;
-
-            /* If we can't move down NLINES lines because we hit
-               the end of the buffer, count in some empty lines.  */
-            if (it.vpos < nlines)
-              {
-                nlines -= it.vpos;
-                extra_line_spacing = it.extra_line_spacing;
-                h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
-              }
-            if (h <= 0)
-              {
-                bidi_unshelve_cache (itdata, false);
-                return Qnil;
-              }
-
-            /* Now find the new top line (starting position) of the window.  */
-            start_display (&it, w, pt);
-            it.current_y = 0;
-            move_it_vertically_backward (&it, h);
-
-            /* If extra line spacing is present, we may move too far
-               back.  This causes the last line to be only partially
-               visible (which triggers redisplay to recenter that line
-               in the middle), so move forward.
-               But ignore extra line spacing on last line, as it is not
-               considered to be part of the visible height of the line.
-            */
-            h += extra_line_spacing;
-            while (-it.current_y > h)
-              move_it_by_lines (&it, 1);
-
-            charpos = IT_CHARPOS (it);
-            bytepos = IT_BYTEPOS (it);
-
-            bidi_unshelve_cache (itdata, false);
-          }
-        else
-          {
-            struct it it;
-            struct text_pos pt;
-            ptrdiff_t nlines = min (PTRDIFF_MAX, iarg);
-            int ht = window_internal_height (w);
-            void *itdata = bidi_shelve_cache ();
-
-            nlines = clip_to_bounds (this_scroll_margin, nlines,
-                                     ht - this_scroll_margin - 1);
-
-            SET_TEXT_POS (pt, PT, PT_BYTE);
-            start_display (&it, w, pt);
-
-            /* Move to the beginning of screen line containing PT.  */
-            move_it_by_lines (&it, 0);
-
-            /* Move back to find the point which is ARG screen lines above PT. 
 */
-            if (nlines > 0)
-              {
-                it.current_y = 0;
-                it.vpos = 0;
-                move_it_by_lines (&it, -nlines);
-              }
-
-            charpos = IT_CHARPOS (it);
-            bytepos = IT_BYTEPOS (it);
-
-            bidi_unshelve_cache (itdata, false);
-          }
-      }
-    else
-      {
-        struct position pos;
-        int ht = window_internal_height (w);
+  /* Don't use redisplay code for initial frames, as the necessary
+     data structures might not be set up yet then.  */
+  if (!FRAME_INITIAL_P (XFRAME (w->frame)))
+    {
+      if (center_p)
+       {
+         struct it it;
+         struct text_pos pt;
+         void *itdata = bidi_shelve_cache ();
+
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+         move_it_vertically_backward (&it, window_box_height (w) / 2);
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+         bidi_unshelve_cache (itdata, false);
+       }
+      else if (iarg < 0)
+       {
+         struct it it;
+         struct text_pos pt;
+         ptrdiff_t nlines = min (PTRDIFF_MAX, -iarg);
+         int extra_line_spacing;
+         int h = window_box_height (w);
+         int ht = window_internal_height (w);
+         void *itdata = bidi_shelve_cache ();
+
+         nlines = clip_to_bounds (this_scroll_margin + 1, nlines,
+                                  ht - this_scroll_margin);
+
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+
+         /* Be sure we have the exact height of the full line containing PT.  
*/
+         move_it_by_lines (&it, 0);
+
+         /* The amount of pixels we have to move back is the window
+            height minus what's displayed in the line containing PT,
+            and the lines below.  */
+         it.current_y = 0;
+         it.vpos = 0;
+         move_it_by_lines (&it, nlines);
 
-        if (center_p)
-          iarg = ht / 2;
-        else if (iarg < 0)
-          iarg += ht;
+         if (it.vpos == nlines)
+           h -= it.current_y;
+         else
+           {
+             /* Last line has no newline.  */
+             h -= line_bottom_y (&it);
+             it.vpos++;
+           }
 
-        /* Don't let it get into the margin at either top or bottom.  */
-        iarg = clip_to_bounds (this_scroll_margin, iarg,
-                               ht - this_scroll_margin - 1);
+         /* Don't reserve space for extra line spacing of last line.  */
+         extra_line_spacing = it.max_extra_line_spacing;
 
-        pos = *vmotion (PT, PT_BYTE, - iarg, w);
-        charpos = pos.bufpos;
-        bytepos = pos.bytepos;
-      }
+         /* If we can't move down NLINES lines because we hit
+            the end of the buffer, count in some empty lines.  */
+         if (it.vpos < nlines)
+           {
+             nlines -= it.vpos;
+             extra_line_spacing = it.extra_line_spacing;
+             h -= nlines * (FRAME_LINE_HEIGHT (it.f) + extra_line_spacing);
+           }
+         if (h <= 0)
+           {
+             bidi_unshelve_cache (itdata, false);
+             return Qnil;
+           }
 
-    /* Set the new window start.  */
-    set_marker_both (w->start, w->contents, charpos, bytepos);
-    w->window_end_valid = false;
+         /* Now find the new top line (starting position) of the window.  */
+         start_display (&it, w, pt);
+         it.current_y = 0;
+         move_it_vertically_backward (&it, h);
+
+         /* If extra line spacing is present, we may move too far
+            back.  This causes the last line to be only partially
+            visible (which triggers redisplay to recenter that line
+            in the middle), so move forward.
+            But ignore extra line spacing on last line, as it is not
+            considered to be part of the visible height of the line.
+         */
+         h += extra_line_spacing;
+         while (-it.current_y > h)
+           move_it_by_lines (&it, 1);
 
-    w->optional_new_start = true;
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
 
-    w->start_at_line_beg = (bytepos == BEGV_BYTE
-                            || FETCH_BYTE (bytepos - 1) == '\n');
+         bidi_unshelve_cache (itdata, false);
+       }
+      else
+       {
+         struct it it;
+         struct text_pos pt;
+         ptrdiff_t nlines = min (PTRDIFF_MAX, iarg);
+         int ht = window_internal_height (w);
+         void *itdata = bidi_shelve_cache ();
 
-    wset_redisplay (w);
+         nlines = clip_to_bounds (this_scroll_margin, nlines,
+                                  ht - this_scroll_margin - 1);
 
-    return Qnil;
-  }
+         SET_TEXT_POS (pt, PT, PT_BYTE);
+         start_display (&it, w, pt);
+
+         /* Move to the beginning of screen line containing PT.  */
+         move_it_by_lines (&it, 0);
+
+         /* Move back to find the point which is ARG screen lines above PT.  */
+         if (nlines > 0)
+           {
+             it.current_y = 0;
+             it.vpos = 0;
+             move_it_by_lines (&it, -nlines);
+           }
+
+         charpos = IT_CHARPOS (it);
+         bytepos = IT_BYTEPOS (it);
+
+         bidi_unshelve_cache (itdata, false);
+       }
+    }
+  else
+    {
+      struct position pos;
+      int ht = window_internal_height (w);
+
+      if (center_p)
+       iarg = ht / 2;
+      else if (iarg < 0)
+       iarg += ht;
+
+      /* Don't let it get into the margin at either top or bottom.  */
+      iarg = clip_to_bounds (this_scroll_margin, iarg,
+                            ht - this_scroll_margin - 1);
+
+      pos = *vmotion (PT, PT_BYTE, - iarg, w);
+      charpos = pos.bufpos;
+      bytepos = pos.bytepos;
+    }
+
+  /* Set the new window start.  */
+  set_marker_both (w->start, w->contents, charpos, bytepos);
+  w->window_end_valid = false;
+
+  w->optional_new_start = true;
+
+  w->start_at_line_beg = (bytepos == BEGV_BYTE
+                         || FETCH_BYTE (bytepos - 1) == '\n');
+
+  wset_redisplay (w);
+
+  return Qnil;
 }
 
 DEFUN ("window-text-width", Fwindow_text_width, Swindow_text_width,
@@ -5869,68 +5808,52 @@ pixels.  */)
 }
 
 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
-       1, 2, "P\ni",
+       1, 1, "P",
        doc: /* Position point relative to window.
 ARG nil means position point at center of window.
 Else, ARG specifies vertical position within the window;
-zero means top of window, negative means relative to bottom of window.
-
-When GROUP is non-nil, and `move-to-window-line-group-function' is set to a
-function, then instead of the above, that function is called with the
-single argument ARG, and its result returned.
-
-If GROUP is non-nil, and WINDOW is part of a group of windows collectively
-displaying a buffer (such as with Follow Mode), position point relative to
-the group of windows as a whole rather than the individual WINDOW.  This
-condition holds when `move-to-window-line-group-function' is set to a
-function, in which case `move-to-window-line' calls the function with the
-argument ARG, then returns its result, instead of doing its normal
-processing.  */)
-  (Lisp_Object arg, Lisp_Object group)
-{
-  if (!NILP (group)
-      && FUNCTIONP (Vmove_to_window_line_group_function))
-    return call1 (Vmove_to_window_line_group_function, arg);
-  {
-    struct window *w = XWINDOW (selected_window);
-    int lines, start;
-    Lisp_Object window;
+zero means top of window, negative means relative to bottom of window.  */)
+  (Lisp_Object arg)
+{
+  struct window *w = XWINDOW (selected_window);
+  int lines, start;
+  Lisp_Object window;
 #if false
-    int this_scroll_margin;
+  int this_scroll_margin;
 #endif
 
-    if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer))
-      /* This test is needed to make sure PT/PT_BYTE make sense in w->contents
-         when passed below to set_marker_both.  */
-      error ("move-to-window-line called from unrelated buffer");
+  if (!(BUFFERP (w->contents) && XBUFFER (w->contents) == current_buffer))
+    /* This test is needed to make sure PT/PT_BYTE make sense in w->contents
+       when passed below to set_marker_both.  */
+    error ("move-to-window-line called from unrelated buffer");
 
-    window = selected_window;
-    start = marker_position (w->start);
-    if (start < BEGV || start > ZV)
-      {
-        int height = window_internal_height (w);
-        Fvertical_motion (make_number (- (height / 2)), window, Qnil);
-        set_marker_both (w->start, w->contents, PT, PT_BYTE);
-        w->start_at_line_beg = !NILP (Fbolp ());
-        w->force_start = true;
-      }
-    else
-      Fgoto_char (w->start);
+  window = selected_window;
+  start = marker_position (w->start);
+  if (start < BEGV || start > ZV)
+    {
+      int height = window_internal_height (w);
+      Fvertical_motion (make_number (- (height / 2)), window, Qnil);
+      set_marker_both (w->start, w->contents, PT, PT_BYTE);
+      w->start_at_line_beg = !NILP (Fbolp ());
+      w->force_start = true;
+    }
+  else
+    Fgoto_char (w->start);
 
-    lines = displayed_window_lines (w);
+  lines = displayed_window_lines (w);
 
 #if false
-    this_scroll_margin = max (0, min (scroll_margin, lines / 4));
+  this_scroll_margin = max (0, min (scroll_margin, lines / 4));
 #endif
 
-    if (NILP (arg))
-      XSETFASTINT (arg, lines / 2);
-    else
-      {
-        EMACS_INT iarg = XINT (Fprefix_numeric_value (arg));
+  if (NILP (arg))
+    XSETFASTINT (arg, lines / 2);
+  else
+    {
+      EMACS_INT iarg = XINT (Fprefix_numeric_value (arg));
 
-        if (iarg < 0)
-          iarg = iarg + lines;
+      if (iarg < 0)
+       iarg = iarg + lines;
 
 #if false /* This code would prevent move-to-window-line from moving point
             to a place inside the scroll margins (which would cause the
@@ -5938,20 +5861,19 @@ processing.  */)
             it is probably better not to install it.  However, it is here
             inside #if false so as not to lose it.  -- rms.  */
 
-        /* Don't let it get into the margin at either top or bottom.  */
-        iarg = max (iarg, this_scroll_margin);
-        iarg = min (iarg, lines - this_scroll_margin - 1);
+      /* Don't let it get into the margin at either top or bottom.  */
+      iarg = max (iarg, this_scroll_margin);
+      iarg = min (iarg, lines - this_scroll_margin - 1);
 #endif
 
-        arg = make_number (iarg);
-      }
+      arg = make_number (iarg);
+    }
 
-    /* Skip past a partially visible first line.  */
-    if (w->vscroll)
-      XSETINT (arg, XINT (arg) + 1);
+  /* Skip past a partially visible first line.  */
+  if (w->vscroll)
+    XSETINT (arg, XINT (arg) + 1);
 
-    return Fvertical_motion (arg, window, Qnil);
-  }
+  return Fvertical_motion (arg, window, Qnil);
 }
 
 
@@ -7225,12 +7147,6 @@ syms_of_window (void)
   DEFSYM (Qclone_of, "clone-of");
   DEFSYM (Qfloor, "floor");
   DEFSYM (Qceiling, "ceiling");
-  DEFSYM (Qwindow_start_group_function, "window-start-group-function");
-  DEFSYM (Qwindow_end_group_function, "window-end-group-function");
-  DEFSYM (Qset_window_start_group_function, "set-window-start-group-function");
-  DEFSYM (Qrecenter_group_function, "recenter-group-function");
-  DEFSYM (Qpos_visible_in_window_p_group_function, 
"pos-visible-in-window-p-group-function");
-  DEFSYM (Qmove_to_window_line_group_function, 
"move-to-window-line-group-function");
 
   staticpro (&Vwindow_list);
 
@@ -7402,72 +7318,6 @@ Note that this optimization can cause the portion of the 
buffer
 displayed after a scrolling operation to be somewhat inaccurate.  */);
   Vfast_but_imprecise_scrolling = false;
 
-  DEFVAR_LISP ("window-start-group-function", Vwindow_start_group_function,
-               doc: /* Function to call for `window-start' when its GROUP 
parameter is non-nil.
-When this variable contains a function, and `window-start' is called with a
-non-nil GROUP parameter, the function is called instead of `window-start''s
-normal action.  `window-start' passes the function its argument WINDOW, which
-might be nil.  The function may recursively call `window-start'.  */);
-  Vwindow_start_group_function = Qnil;
-  Fmake_variable_buffer_local (Qwindow_start_group_function);
-  Fput (Qwindow_start_group_function, Qpermanent_local, Qt);
-
-  DEFVAR_LISP ("window-end-group-function", Vwindow_end_group_function,
-               doc: /* Function to call for `window-end' if its GROUP 
parameter is non-nil.
-When this variable contains a function, and `window-end' is called with a
-non-nil GROUP parameter, the function is called instead of `window-end''s
-normal action.  `window-end' passes the function its two parameters WINDOW,
-and UPDATE.  The function may call `window-end' recursively.  */);
-  Vwindow_end_group_function = Qnil;
-  Fmake_variable_buffer_local (Qwindow_end_group_function);
-  Fput (Qwindow_end_group_function, Qpermanent_local, Qt);
-
-  DEFVAR_LISP ("set-window-start-group-function",
-               Vset_window_start_group_function,
-               doc: /* The function to call for `set-window-start' when its 
GROUP parameter is non-nil.
-When this variable contains a function, and `set-window-start' is called
-with a non-nil GROUP parameter, the function is called instead of
-`set-window-start''s normal action.  `set-window-start' passes the function
-its three parameters WINDOW, POS, and NOFORCE.  The function may call
-`set-window-start' recursively.  */);
-  Vset_window_start_group_function = Qnil;
-  Fmake_variable_buffer_local (Qset_window_start_group_function);
-  Fput (Qset_window_start_group_function, Qpermanent_local, Qt);
-
-  DEFVAR_LISP ("recenter-group-function", Vrecenter_group_function,
-               doc: /* Function to call for `recenter' when its GROUP 
parameter is non-nil.
-When this variable contains a function, and `recenter' is called with a
-non-nil GROUP parameter, the function is called instead of `recenter''s
-normal action.  `recenter' passes the function its parameter ARG.  The
-function may call `recenter' recursively.  */);
-  Vrecenter_group_function = Qnil;
-  Fmake_variable_buffer_local (Qrecenter_group_function);
-  Fput (Qrecenter_group_function, Qpermanent_local, Qt);
-
-  DEFVAR_LISP ("pos-visible-in-window-p-group-function",
-               Vpos_visible_in_window_p_group_function,
-               doc: /*  Function for `pos-visible-in-window-p' when its GROUP 
parameter is non-nil.
-When this variable contains a function, and `pos-visible-in-window-p' is
-called with a non-nil GROUP parameter, the function is called instead of
-`pos-visible-in-window-p''s normal action.  `pos-visible-in-window-p'
-passes the function its three parameters POS, WINDOW, and PARTIALLY.  The
-function may call `pos-visible-in-window-p' recursively.  */);
-  Vpos_visible_in_window_p_group_function = Qnil;
-  Fmake_variable_buffer_local (Qpos_visible_in_window_p_group_function);
-  Fput (Qpos_visible_in_window_p_group_function, Qpermanent_local, Qt);
-
-  DEFVAR_LISP ("move-to-window-line-group-function",
-               Vmove_to_window_line_group_function,
-               doc: /* Function for `move-to-window-line' when its GROUP 
parameter is non-nil.
-When this variable contains a function, and `move-to-window-line' is
-called with a non-nil GROUP parameter, the function is called instead of
-`move-to-window-line''s normal action.  `move-to-window-line' passes the
-function its parameter ARG.  The function may call `move-to-window-line'
-recursively.  */);
-  Vmove_to_window_line_group_function = Qnil;
-  Fmake_variable_buffer_local (Qmove_to_window_line_group_function);
-  Fput (Qmove_to_window_line_group_function, Qpermanent_local, Qt);
-
   defsubr (&Sselected_window);
   defsubr (&Sminibuffer_window);
   defsubr (&Swindow_minibuffer_p);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]