Function: follow-adjust-window

follow-adjust-window is a byte-compiled function defined in follow.el.gz.

Signature

(follow-adjust-window WIN)

Documentation

Adjust the window WIN and its followers.

Source Code

;; Defined in /usr/src/emacs/lisp/follow.el.gz
;; NOTE: to debug follow-mode with edebug, it is helpful to add
;; `follow-post-command-hook' to `post-command-hook' temporarily.  Do
;; this locally to the target buffer with, say,:
;; M-: (add-hook 'post-command-hook 'follow-post-command-hook t t)
;; .

(defun follow-adjust-window (win)
  "Adjust the window WIN and its followers."
  (cl-assert (eq (window-buffer win) (current-buffer)))

  ;; Have we moved out of or into a follow-mode window group?
  ;; If so, attend to the visibility of the cursors.
  (when (not (eq (current-buffer) follow-prev-buffer))
    ;; Do we need to switch off cursor handling in the previous buffer?
    (when (buffer-live-p follow-prev-buffer)
      (with-current-buffer follow-prev-buffer
        (when (and follow-mode
                   (local-variable-p 'cursor-in-non-selected-windows))
          (setq cursor-in-non-selected-windows
                (default-value 'cursor-in-non-selected-windows)))))
    ;; Do we need to switch on cursor handling in the current buffer?
    (when (and follow-mode
               (local-variable-p 'cursor-in-non-selected-windows))
      (setq cursor-in-non-selected-windows nil))
    (when (buffer-live-p (current-buffer))
      (setq follow-prev-buffer (current-buffer))))

  (when (and follow-mode
             (not (window-minibuffer-p win)))
    (let ((windows (follow-all-followers win)))
      ;; If we've explicitly scrolled, align the windows first.
      (when follow-fixed-window
	(follow-debug-message "fixed")
	(follow-redisplay windows win)
	(goto-char (follow-get-scrolled-point (point) windows))
	(setq follow-fixed-window nil))
      (let* ((dest (point))
	     (win-start-end (progn
			      (follow-update-window-start (car windows))
			      (follow-windows-start-end windows)))
	     (aligned (follow-windows-aligned-p win-start-end))
	     (visible (follow-pos-visible dest win win-start-end))
	     selected-window-up-to-date)
	(unless (and aligned visible)
	  (setq follow-windows-start-end-cache nil))

	;; Select a window to display point.
	(unless follow-internal-force-redisplay
	  (if (eq dest (point-max))
	      ;; Be careful at point-max: the display can be aligned
	      ;; while DEST can be visible in several windows.
	      (cond
	       ;; Select the current window, but only when the display
	       ;; is correct. (When inserting characters in a tail
	       ;; window, the display is not correct, as they are
	       ;; shown twice.)
	       ;;
	       ;; Never stick to the current window after a deletion.
	       ;; Otherwise, when typing `DEL' in a window showing
	       ;; only the end of the file, a character would be
	       ;; removed from the window above, which is very
	       ;; unintuitive.
	       ((and visible
		     aligned
		     (not (memq this-command
				'(backward-delete-char
				  delete-backward-char
				  backward-delete-char-untabify
				  kill-region))))
		(follow-debug-message "Max: same"))
	       ;; If the end is visible, and the window doesn't
	       ;; seems like it just has been moved, select it.
	       ((follow-select-if-end-visible win-start-end)
		(follow-debug-message "Max: end visible")
		(setq visible t aligned nil)
		(goto-char dest))
	       ;; Just show the end...
	       (t
		(follow-debug-message "Max: default")
		(select-window (car (last windows)))
		(goto-char dest)
		(setq visible nil aligned nil)))

	    ;; We're not at the end, here life is much simpler.
	    (cond
	     ;; This is the normal case!
	     ;; It should be optimized for speed.
	     ((and visible aligned)
	      (follow-debug-message "same"))
	     ;; Pick a position in any window.  If the display is ok,
	     ;; this picks the `correct' window.
	     ((follow-select-if-visible dest win-start-end)
	      (follow-debug-message "visible")
	      (goto-char dest)
	      ;; Perform redisplay, in case line is partially visible.
	      (setq visible nil))
	     ;; Not visible anywhere else, lets pick this one.
	     (visible
	      (follow-debug-message "visible in selected."))
	     ;; If DEST is before the first window start, select the
	     ;; first window.
	     ((< dest (nth 1 (car win-start-end)))
	      (follow-debug-message "before first")
	      (select-window (car windows))
	      (goto-char dest)
	      (setq visible nil aligned nil))
	     ;; If we can position the cursor without moving the first
	     ;; window, do it. This is the case that catches `RET' at
	     ;; the bottom of a window.
	     ((follow-select-if-visible-from-first dest windows)
	      (follow-debug-message "Below first")
	      (setq visible t aligned t))
	     ;; None of the above.  Stick to the selected window.
	     (t
	      (follow-debug-message "None")
	      (setq visible nil aligned nil))))

	  ;; If a new window was selected, make sure that the old is
	  ;; not scrolled when point is outside the window.
	  (unless (eq win (selected-window))
	    (let ((p (window-point win)))
	      (set-window-start win (window-start win) nil)
              (if (nth 2 (pos-visible-in-window-p p win t))
                  ;; p is in a partially visible line.  We can't leave
                  ;; window-point there, because C-x o back into WIN
                  ;; would then fail.
                  (with-selected-window win
                    (forward-line)) ; redisplay will recenter it in WIN.
                (set-window-point win p)))))

	(unless visible
	  ;; If point may not be visible in the selected window,
	  ;; perform a redisplay; this ensures scrolling.
	  (let ((opoint (point)))
	    (redisplay)
	    ;; If this `redisplay' moved point, we got clobbered by a
	    ;; previous call to `set-window-start'.  Try again.
	    (when (/= (point) opoint)
	      (goto-char opoint)
	      (redisplay)))

	  (setq selected-window-up-to-date t)
	  (follow-avoid-tail-recenter)
	  (setq win-start-end (follow-windows-start-end windows)
		follow-windows-start-end-cache nil
		aligned nil))

	;; Now redraw the windows around the selected window.
	(unless (and (not follow-internal-force-redisplay)
		     (or aligned
			 (follow-windows-aligned-p win-start-end))
		     (follow-point-visible-all-windows-p win-start-end))
	  (setq follow-internal-force-redisplay nil)
	  (follow-redisplay windows (selected-window)
			    selected-window-up-to-date)
	  (setq win-start-end (follow-windows-start-end windows)
		follow-windows-start-end-cache nil)
	  ;; Point can end up in another window when DEST is at
	  ;; the beginning of the buffer and the selected window is
	  ;; not the first.  It can also happen when long lines are
	  ;; used and there is a big difference between the width of
	  ;; the windows.  (When scrolling one line in a wide window
	  ;; which will cause a move larger that an entire small
	  ;; window.)
	  (unless (follow-pos-visible dest win win-start-end)
	    (follow-select-if-visible dest win-start-end)
	    (goto-char dest)))

	;; If the region is visible, make it look good when spanning
	;; multiple windows.
	(when (region-active-p)
	  (follow-maximize-region
	   (selected-window) windows win-start-end))))

    ;; Whether or not the buffer was in follow mode, update windows
    ;; displaying the tail so that Emacs won't recenter them.
    (follow-avoid-tail-recenter)))