]> code.delx.au - gnu-emacs/blobdiff - lisp/window.el
Update copyright year to 2016
[gnu-emacs] / lisp / window.el
index 238e53ca76a900e12cdbdd4d861b87c5918b7474..620f4ed26a9fa29318a77def2edeee6d667a7a79 100644 (file)
@@ -1,6 +1,6 @@
 ;;; window.el --- GNU Emacs window commands aside from those written in C
 
-;; Copyright (C) 1985, 1989, 1992-1994, 2000-2015 Free Software
+;; Copyright (C) 1985, 1989, 1992-1994, 2000-2016 Free Software
 ;; Foundation, Inc.
 
 ;; Maintainer: emacs-devel@gnu.org
@@ -2299,8 +2299,8 @@ selected frame and no others."
 (defun get-buffer-window-list (&optional buffer-or-name minibuf all-frames)
   "Return list of all windows displaying BUFFER-OR-NAME, or nil if none.
 BUFFER-OR-NAME may be a buffer or the name of an existing buffer
-and defaults to the current buffer.  Windows are scanned starting
-with the selected window.
+and defaults to the current buffer.  If the selected window displays
+BUFFER-OR-NAME, it will be the first in the resulting list.
 
 MINIBUF t means include the minibuffer window even if the
 minibuffer is not active.  MINIBUF nil or omitted means include
@@ -3160,7 +3160,7 @@ move it as far as possible in the desired direction."
   (let* ((frame (window-frame window))
         (minibuffer-window (minibuffer-window frame))
         (right window)
-        left this-delta min-delta max-delta ignore)
+        left first-left first-right this-delta min-delta max-delta ignore)
 
     (unless pixelwise
       (setq pixelwise t)
@@ -3188,6 +3188,7 @@ move it as far as possible in the desired direction."
      (t
       ;; Set LEFT to the first resizable window on the left.  This step is
       ;; needed to handle fixed-size windows.
+      (setq first-left left)
       (while (and left
                  (or (window-size-fixed-p left horizontal)
                      (and (< delta 0)
@@ -3200,8 +3201,10 @@ move it as far as possible in the desired direction."
                                (not (window-combined-p left horizontal))))
                    (window-left left)))))
       (unless left
+       ;; We have to resize a size-preserved window.  Start again with
+       ;; the window initially on the left.
        (setq ignore 'preserved)
-       (setq left window)
+       (setq left first-left)
        (while (and left
                    (or (window-size-fixed-p left horizontal 'preserved)
                        (<= (window-size left horizontal t)
@@ -3220,6 +3223,7 @@ move it as far as possible in the desired direction."
 
       ;; Set RIGHT to the first resizable window on the right.  This step
       ;; is needed to handle fixed-size windows.
+      (setq first-right right)
       (while (and right
                  (or (window-size-fixed-p right horizontal)
                      (and (> delta 0)
@@ -3232,12 +3236,14 @@ move it as far as possible in the desired direction."
                                (not (window-combined-p right horizontal))))
                    (window-right right)))))
       (unless right
+       ;; We have to resize a size-preserved window.  Start again with
+       ;; the window initially on the right.
        (setq ignore 'preserved)
-       (setq right (window-right window))
+       (setq right first-right)
        (while (and right
                    (or (window-size-fixed-p right horizontal 'preserved))
                    (<= (window-size right horizontal t)
-                       (window-min-size right horizontal nil t)))
+                       (window-min-size right horizontal 'preserved t)))
          (setq right
                (or (window-right right)
                    (progn
@@ -3422,6 +3428,134 @@ WINDOW pixelwise."
    (- (window-min-delta window t nil nil nil nil window-resize-pixelwise))
    t nil window-resize-pixelwise))
 \f
+;;; Window edges
+(defun window-edges (&optional window body absolute pixelwise)
+  "Return a list of the edge distances of WINDOW.
+WINDOW must be a valid window and defaults to the selected one.
+The list returned has the form (LEFT TOP RIGHT BOTTOM).
+
+If the optional argument BODY is nil, this means to return the
+edges corresponding to the total size of WINDOW.  BODY non-nil
+means to return the edges of WINDOW's body (aka text area).  If
+BODY is non-nil, WINDOW must specify a live window.
+
+Optional argument ABSOLUTE nil means to return edges relative to
+the position of WINDOW's native frame.  ABSOLUTE non-nil means to
+return coordinates relative to the origin - the position (0, 0) -
+of FRAME's display.  On non-graphical systems this argument has
+no effect.
+
+Optional argument PIXELWISE nil means to return the coordinates
+in terms of the canonical character width and height of WINDOW's
+frame, rounded if necessary.  PIXELWISE non-nil means to return
+the coordinates in pixels where the values for RIGHT and BOTTOM
+are one more than the actual value of these edges.  Note that if
+ABSOLUTE is non-nil, PIXELWISE is implicitly non-nil too."
+  (let* ((window (window-normalize-window window body))
+        (frame (window-frame window))
+        (border-width (frame-border-width frame))
+        (char-width (frame-char-width frame))
+        (char-height (frame-char-height frame))
+        (left (if pixelwise
+                  (+ (window-pixel-left window) border-width)
+                (+ (window-left-column window)
+                   (/ border-width char-width))))
+        (left-body
+         (when body
+           (+ (window-pixel-left window) border-width
+              (if (eq (car (window-current-scroll-bars window)) 'left)
+                  (window-scroll-bar-width window)
+                0)
+              (nth 0 (window-fringes window))
+              (* (or (nth 0 (window-margins window)) 0) char-width))))
+        (top (if pixelwise
+                 (+ (window-pixel-top window) border-width)
+               (+ (window-top-line window)
+                  (/ border-width char-height))))
+        (top-body
+         (when body
+           (+ (window-pixel-top window) border-width
+              (window-header-line-height window))))
+        (right (+ left (if pixelwise
+                           (window-pixel-width window)
+                         (window-total-width window))))
+        (right-body (and body (+ left-body (window-body-width window t))))
+        (bottom (+ top (if pixelwise
+                           (window-pixel-height window)
+                         (window-total-height window))))
+        (bottom-body (and body (+ top-body (window-body-height window t))))
+        left-off right-off)
+    (if absolute
+       (let* ((native-edges (frame-edges frame 'native-edges))
+              (left-off (nth 0 native-edges))
+              (top-off (nth 1 native-edges)))
+             (if body
+                 (list (+ left-body left-off) (+ top-body top-off)
+                       (+ right-body left-off) (+ bottom-body top-off))
+               (list (+ left left-off) (+ top top-off)
+                     (+ right left-off) (+ bottom top-off))))
+      (if body
+         (if pixelwise
+             (list left-body top-body right-body bottom-body)
+           (list (/ left-body char-width) (/ top-body char-height)
+                 ;; Round up.
+                 (/ (+ right-body char-width -1) char-width)
+                 (/ (+ bottom-body char-height -1) char-height)))
+       (list left top right bottom)))))
+
+(defun window-body-edges (&optional window)
+  "Return a list of the edge coordinates of WINDOW's body.
+The return value is that of `window-edges' called with argument
+BODY non-nil."
+  (window-edges window t))
+(defalias 'window-inside-edges 'window-body-edges)
+
+(defun window-pixel-edges (&optional window)
+  "Return a list of the edge pixel coordinates of WINDOW.
+The return value is that of `window-edges' called with argument
+PIXELWISE non-nil."
+  (window-edges window nil nil t))
+
+(defun window-body-pixel-edges (&optional window)
+  "Return a list of the edge pixel coordinates of WINDOW's body.
+The return value is that of `window-edges' called with arguments
+BODY and PIXELWISE non-nil."
+  (window-edges window t nil t))
+(defalias 'window-inside-pixel-edges 'window-body-pixel-edges)
+
+(defun window-absolute-pixel-edges (&optional window)
+  "Return a list of the edge pixel coordinates of WINDOW.
+The return value is that of `window-edges' called with argument
+ABSOLUTE non-nil."
+  (window-edges window nil t t))
+
+(defun window-absolute-body-pixel-edges (&optional window)
+  "Return a list of the edge pixel coordinates of WINDOW's text area.
+The return value is that of `window-edges' called with arguments
+BODY and ABSOLUTE non-nil."
+  (window-edges window t t t))
+(defalias 'window-inside-absolute-pixel-edges 'window-absolute-body-pixel-edges)
+
+(defun window-absolute-pixel-position (&optional position window)
+  "Return display coordinates of POSITION in WINDOW.
+If the buffer position POSITION is visible in window WINDOW,
+return the display coordinates of the upper/left corner of the
+glyph at POSITION.  The return value is a cons of the X- and
+Y-coordinates of that corner, relative to an origin at (0, 0) of
+WINDOW's display.  Return nil if POSITION is not visible in
+WINDOW.
+
+WINDOW must be a live window and defaults to the selected window.
+POSITION defaults to the value of `window-point' of WINDOW."
+  (let* ((window (window-normalize-window window t))
+        (pos-in-window
+         (pos-visible-in-window-p
+          (or position (window-point window)) window t)))
+    (when pos-in-window
+      (let ((edges (window-absolute-body-pixel-edges window)))
+       (cons (+ (nth 0 edges) (nth 0 pos-in-window))
+             (+ (nth 1 edges) (nth 1 pos-in-window)))))))
+\f
 (defun frame-root-window-p (window)
   "Return non-nil if WINDOW is the root window of its frame."
   (eq window (frame-root-window window)))
@@ -3573,7 +3707,7 @@ and no others."
 (defun window-deletable-p (&optional window)
   "Return t if WINDOW can be safely deleted from its frame.
 WINDOW must be a valid window and defaults to the selected one.
-Return 'frame if deleting WINDOW should also delete its frame."
+Return `frame' if deleting WINDOW should also delete its frame."
   (setq window (window-normalize-window window))
 
   (unless (or ignore-window-parameters
@@ -4717,8 +4851,9 @@ frame.  The selected window is not changed by this function."
              (set-window-parameter (window-parent new) 'window-atom t))
            (set-window-parameter new 'window-atom t)))
 
-         ;; Sanitize sizes.
-         (window--sanitize-window-sizes frame horizontal)
+         ;; Sanitize sizes unless SIZE was specified.
+         (unless size
+            (window--sanitize-window-sizes frame horizontal))
 
          (run-window-configuration-change-hook frame)
          (run-window-scroll-functions new)
@@ -5468,18 +5603,18 @@ windows can get as small as `window-safe-min-height' and
 (defun display-buffer-record-window (type window buffer)
   "Record information for window used by `display-buffer'.
 TYPE specifies the type of the calling operation and must be one
-of the symbols 'reuse (when WINDOW existed already and was
-reused for displaying BUFFER), 'window (when WINDOW was created
-on an already existing frame), or 'frame (when WINDOW was
+of the symbols `reuse' (when WINDOW existed already and was
+reused for displaying BUFFER), `window' (when WINDOW was created
+on an already existing frame), or `frame' (when WINDOW was
 created on a new frame).  WINDOW is the window used for or created
 by the `display-buffer' routines.  BUFFER is the buffer that
 shall be displayed.
 
 This function installs or updates the quit-restore parameter of
 WINDOW.  The quit-restore parameter is a list of four elements:
-The first element is one of the symbols 'window, 'frame, 'same or
-'other.  The second element is either one of the symbols 'window
-or 'frame or a list whose elements are the buffer previously
+The first element is one of the symbols `window', `frame', `same' or
+`other'.  The second element is either one of the symbols `window'
+or `frame' or a list whose elements are the buffer previously
 shown in the window, that buffer's window start and window point,
 and the window's height.  The third element is the window
 selected at the time the parameter was created.  The fourth
@@ -5734,7 +5869,7 @@ one of the regular expressions in `special-display-regexps'.
 
 This variable can be set in your init file, like this:
 
-  (setq special-display-frame-alist '((width . 80) (height . 20)))
+  (setq special-display-frame-alist \\='((width . 80) (height . 20)))
 
 These supersede the values given in `default-frame-alist'."
   :type '(repeat (cons :format "%v"
@@ -6244,6 +6379,7 @@ The actual non-nil value of this variable will be copied to the
           (const display-buffer-at-bottom)
           (const display-buffer-in-previous-window)
           (const display-buffer-use-some-window)
+          (const display-buffer-use-some-frame)
           (function :tag "Other function"))
   "Custom type for `display-buffer' action functions.")
 
@@ -6356,7 +6492,7 @@ action.  Its form is described below.
 Optional argument FRAME, if non-nil, acts like an additional
 ALIST entry (reusable-frames . FRAME) to the action list of ACTION,
 specifying the frame(s) to search for a window that is already
-displaying the buffer.  See `display-buffer-reuse-window'
+displaying the buffer.  See `display-buffer-reuse-window'.
 
 If ACTION is non-nil, it should have the form (FUNCTION . ALIST),
 where FUNCTION is either a function or a list of functions, and
@@ -6388,6 +6524,7 @@ Available action functions include:
  `display-buffer-pop-up-window'
  `display-buffer-in-previous-window'
  `display-buffer-use-some-window'
+ `display-buffer-use-some-frame'
 
 Recognized alist entries include:
 
@@ -6426,9 +6563,9 @@ Recognized alist entries include:
     of not displaying the buffer and FUNCTION can safely return
     a non-window value to suppress displaying.
 
- `preserve-size' -- Value should be either '(t . nil)' to
-    preserve the width of the window, '(nil . t)' to preserve its
-    height or '(t . t)' to preserve both.
+ `preserve-size' -- Value should be either (t . nil) to
+    preserve the width of the window, (nil . t) to preserve its
+    height or (t . t) to preserve both.
 
 The ACTION argument to `display-buffer' can also have a non-nil
 and non-list value.  This means to display the buffer in a window
@@ -6490,7 +6627,7 @@ its documentation for additional customization information."
 
 (defun display-buffer-use-some-frame (buffer alist)
   "Display BUFFER in an existing frame that meets a predicate
-(by default any frame other than the current frame).  If
+\(by default any frame other than the current frame).  If
 successful, return the window used; otherwise return nil.
 
 If ALIST has a non-nil `inhibit-switch-frame' entry, avoid
@@ -6499,8 +6636,12 @@ raising the frame.
 If ALIST has a non-nil `frame-predicate' entry, its value is a
 function taking one argument (a frame), returning non-nil if the
 frame is a candidate; this function replaces the default
-predicate."
-  (let* ((predicate (or (cdr (assoc 'frame-predicate alist))
+predicate.
+
+If ALIST has a non-nil `inhibit-same-window' entry, avoid using
+the currently selected window (only useful with a frame-predicate
+that allows the selected frame)."
+  (let* ((predicate (or (cdr (assq 'frame-predicate alist))
                         (lambda (frame)
                           (and
                            (not (eq frame (selected-frame)))
@@ -6510,7 +6651,7 @@ predicate."
                                   (frame-first-window frame)))))
                           )))
          (frame (car (filtered-frame-list predicate)))
-         (window (and frame (get-lru-window frame))))
+         (window (and frame (get-lru-window frame nil (cdr (assq 'inhibit-same-window alist))))))
     (when window
       (prog1
           (window--display-buffer
@@ -6705,7 +6846,7 @@ selected frame."
     (or (and bottom-window-shows-buffer
             (window--display-buffer
              buffer bottom-window 'reuse alist display-buffer-mark-dedicated))
-     (and (not (frame-parameter nil 'unsplittable))
+       (and (not (frame-parameter nil 'unsplittable))
             (let (split-width-threshold)
               (setq window (window--try-to-split-window bottom-window alist)))
             (window--display-buffer
@@ -7728,6 +7869,152 @@ Return non-nil if the window was shrunk, nil otherwise."
        (with-current-buffer buffer-to-kill
         (remove-hook 'kill-buffer-hook delete-window-hook t))))))
 
+\f
+;;;
+;; Groups of windows (Follow Mode).
+;;
+;; This section of functions extends the functionality of some window
+;; manipulating commands to groups of windows cooperatively
+;; 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-window-group-function nil)
+(make-variable-buffer-local 'recenter-window-group-function)
+(put 'recenter-window-group-function 'permanent-local t)
+(defun recenter-window-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-window-group-function)
+      (funcall recenter-window-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)))
+
 \f
 (defvar recenter-last-op nil
   "Indicates the last recenter operation performed.