]> code.delx.au - gnu-emacs/blobdiff - lisp/window.el
Merge branch 'emacs-24'
[gnu-emacs] / lisp / window.el
index 7d76649d7cfaa952d283236f1a6e8547ad8b46ee..b1acd93926c3cb7e68bfb05b2832d4fc2343ad05 100644 (file)
@@ -108,7 +108,7 @@ Return the buffer."
       ;; Return the buffer.
       buffer)))
 
-(defun temp-buffer-window-show (&optional buffer action)
+(defun temp-buffer-window-show (buffer &optional action)
   "Show temporary buffer BUFFER in a window.
 Return the window showing BUFFER.  Pass ACTION as action argument
 to `display-buffer'."
@@ -185,16 +185,19 @@ argument replaces this)."
   (let ((buffer (make-symbol "buffer"))
        (window (make-symbol "window"))
        (value (make-symbol "value")))
-    `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name))
-           (standard-output ,buffer)
-           ,window ,value)
-       (setq ,value (progn ,@body))
-       (with-current-buffer ,buffer
-        (setq ,window (temp-buffer-window-show ,buffer ,action)))
+    (macroexp-let2* nil ((vbuffer-or-name buffer-or-name)
+                        (vaction action)
+                        (vquit-function quit-function))
+      `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+             (standard-output ,buffer)
+             ,window ,value)
+        (setq ,value (progn ,@body))
+        (with-current-buffer ,buffer
+          (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
 
-       (if (functionp ,quit-function)
-          (funcall ,quit-function ,window ,value)
-        ,value))))
+        (if (functionp ,vquit-function)
+            (funcall ,vquit-function ,window ,value)
+          ,value)))))
 
 (defmacro with-current-buffer-window (buffer-or-name action quit-function &rest body)
   "Evaluate BODY with a buffer BUFFER-OR-NAME current and show that buffer.
@@ -205,16 +208,50 @@ BODY."
   (let ((buffer (make-symbol "buffer"))
        (window (make-symbol "window"))
        (value (make-symbol "value")))
-    `(let* ((,buffer (temp-buffer-window-setup ,buffer-or-name))
-           (standard-output ,buffer)
-           ,window ,value)
-       (with-current-buffer ,buffer
-        (setq ,value (progn ,@body))
-        (setq ,window (temp-buffer-window-show ,buffer ,action)))
+    (macroexp-let2* nil ((vbuffer-or-name buffer-or-name)
+                        (vaction action)
+                        (vquit-function quit-function))
+      `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+             (standard-output ,buffer)
+             ,window ,value)
+        (with-current-buffer ,buffer
+          (setq ,value (progn ,@body))
+          (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+
+        (if (functionp ,vquit-function)
+            (funcall ,vquit-function ,window ,value)
+          ,value)))))
+
+(defmacro with-displayed-buffer-window (buffer-or-name action quit-function &rest body)
+  "Show a buffer BUFFER-OR-NAME and evaluate BODY in that buffer.
+This construct is like `with-current-buffer-window' but unlike that
+displays the buffer specified by BUFFER-OR-NAME before running BODY."
+  (declare (debug t))
+  (let ((buffer (make-symbol "buffer"))
+       (window (make-symbol "window"))
+       (value (make-symbol "value")))
+    (macroexp-let2* nil ((vbuffer-or-name buffer-or-name)
+                        (vaction action)
+                        (vquit-function quit-function))
+      `(let* ((,buffer (temp-buffer-window-setup ,vbuffer-or-name))
+             (standard-output ,buffer)
+             ,window ,value)
+        (with-current-buffer ,buffer
+          (setq ,window (temp-buffer-window-show ,buffer ,vaction)))
+
+        (let ((inhibit-read-only t)
+              (inhibit-modification-hooks t))
+          (setq ,value (progn ,@body)))
+
+        (set-window-point ,window (point-min))
+
+        (when (functionp (cdr (assq 'window-height (cdr ,vaction))))
+          (ignore-errors
+            (funcall (cdr (assq 'window-height (cdr ,vaction))) ,window)))
 
-       (if (functionp ,quit-function)
-          (funcall ,quit-function ,window ,value)
-        ,value))))
+        (if (functionp ,vquit-function)
+            (funcall ,vquit-function ,window ,value)
+          ,value)))))
 
 ;; The following two functions are like `window-next-sibling' and
 ;; `window-prev-sibling' but the WINDOW argument is _not_ optional (so
@@ -341,9 +378,9 @@ Anything less might crash Emacs.")
 (defcustom window-min-height 4
   "The minimum total height, in lines, of any window.
 The value has to accommodate one text line, a mode and header
-line, and a bottom divider, if present.  A value less than
-`window-safe-min-height' is ignored.  The value of this variable
-is honored when windows are resized or split.
+line, a horizontal scroll bar and a bottom divider, if present.
+A value less than `window-safe-min-height' is ignored.  The value
+of this variable is honored when windows are resized or split.
 
 Applications should never rebind this variable.  To resize a
 window to a height less than the one specified here, an
@@ -706,6 +743,15 @@ number of slots on that side."
      (integer :tag "Number" :value 3 :size 5)))
   :group 'windows)
 
+(defun window--side-window-p (window)
+  "Return non-nil if WINDOW is a side window or the parent of one."
+  (or (window-parameter window 'window-side)
+      (and (window-child window)
+          (or (window-parameter
+               (window-child window) 'window-side)
+              (window-parameter
+               (window-last-child window) 'window-side)))))
+
 (defun window--major-non-side-window (&optional frame)
   "Return the major non-side window of frame FRAME.
 The optional argument FRAME must be a live frame and defaults to
@@ -1100,11 +1146,12 @@ dumping to it."
        (format "frame text pixel: %s x %s   cols/lines: %s x %s\n"
               (frame-text-width frame) (frame-text-height frame)
               (frame-text-cols frame) (frame-text-lines frame))
-       (format "tool: %s  scroll: %s  fringe: %s  border: %s  right: %s  bottom: %s\n\n"
+       (format "tool: %s  scroll: %s/%s  fringe: %s  border: %s  right: %s  bottom: %s\n\n"
               (if (fboundp 'tool-bar-height)
                   (tool-bar-height frame t)
                 "0")
               (frame-scroll-bar-width frame)
+              (frame-scroll-bar-height frame)
               (frame-fringe-width frame)
               (frame-border-width frame)
               (frame-right-divider-width frame)
@@ -1234,12 +1281,14 @@ of WINDOW."
          value)
       (with-current-buffer (window-buffer window)
        (cond
+        ((window-minibuffer-p window)
+         (if pixelwise (frame-char-height (window-frame window)) 1))
         ((and (not (window--size-ignore-p window ignore))
               (window-size-fixed-p window horizontal))
          ;; The minimum size of a fixed size window is its size.
          (window-size window horizontal pixelwise))
-        ((or (eq ignore 'safe) (eq ignore window))
-         ;; If IGNORE equals `safe' or WINDOW return the safe values.
+        ((eq ignore 'safe)
+         ;; If IGNORE equals `safe' return the safe value.
          (window-safe-min-size window horizontal pixelwise))
         (horizontal
          ;; For the minimum width of a window take fringes and
@@ -1250,8 +1299,11 @@ of WINDOW."
          ;; `window-min-width'.
          (let* ((char-size (frame-char-size window t))
                 (fringes (window-fringes window))
+                (margins (window-margins window))
                 (pixel-width
                  (+ (window-safe-min-size window t t)
+                    (* (or (car margins) 0) char-size)
+                    (* (or (cdr margins) 0) char-size)
                     (car fringes) (cadr fringes)
                     (window-scroll-bar-width window)
                     (window-right-divider-width window))))
@@ -1263,7 +1315,7 @@ of WINDOW."
                   (* (ceiling pixel-width char-size) char-size))
                 (if (window--size-ignore-p window ignore)
                     0
-                  (window-min-pixel-width)))
+                  (window-min-pixel-width window)))
              (max
               (ceiling pixel-width char-size)
               (if (window--size-ignore-p window ignore)
@@ -1273,6 +1325,7 @@ of WINDOW."
                (pixel-height
                 (+ (window-safe-min-size window nil t)
                    (window-header-line-height window)
+                   (window-scroll-bar-height window)
                    (window-mode-line-height window)
                    (window-bottom-divider-width window))))
            (if pixelwise
@@ -1283,7 +1336,7 @@ of WINDOW."
                   (* (ceiling pixel-height char-size) char-size))
                 (if (window--size-ignore-p window ignore)
                     0
-                  (window-min-pixel-height)))
+                  (window-min-pixel-height window)))
              (max (ceiling pixel-height char-size)
                   (if (window--size-ignore-p window ignore)
                       0
@@ -1480,6 +1533,18 @@ by which WINDOW can be shrunk."
       (window--min-delta-1
        window (- size minimum) horizontal ignore trail noup pixelwise)))))
 
+(defun frame-windows-min-size (&optional frame horizontal pixelwise)
+  "Return minimum number of lines of FRAME's windows.
+HORIZONTAL non-nil means return number of columns of FRAME's
+windows.  PIXELWISE non-nil means return sizes in pixels."
+  (setq frame (window-normalize-frame frame))
+  (let* ((root (frame-root-window frame))
+        (mini (window-next-sibling root)))
+    (+ (window-min-size root horizontal nil pixelwise)
+       (if (and mini (not horizontal))
+          (window-min-size mini horizontal nil pixelwise)
+        0))))
+
 (defun window--max-delta-1 (window delta &optional horizontal ignore trail noup pixelwise)
   "Internal function of `window-max-delta'."
   (if (not (window-parent window))
@@ -1680,9 +1745,6 @@ doc-string of `window-resizable'."
 (defalias 'window-height 'window-total-height)
 (defalias 'window-width 'window-body-width)
 
-;; Eventually the following two should work pixelwise.
-
-;; See discussion in bug#4543.
 (defun window-full-height-p (&optional window)
   "Return t if WINDOW is as high as its containing frame.
 More precisely, return t if and only if the total height of
@@ -1690,8 +1752,10 @@ WINDOW equals the total height of the root window of WINDOW's
 frame.  WINDOW must be a valid window and defaults to the
 selected one."
   (setq window (window-normalize-window window))
-  (= (window-pixel-height window)
-     (window-pixel-height (frame-root-window window))))
+  (if (window-minibuffer-p window)
+      (eq window (frame-root-window (window-frame window)))
+    (= (window-pixel-height window)
+       (window-pixel-height (frame-root-window window)))))
 
 (defun window-full-width-p (&optional window)
   "Return t if WINDOW is as wide as its containing frame.
@@ -1715,28 +1779,26 @@ optional argument PIXELWISE is passed to the functions."
     (window-body-height window pixelwise)))
 
 (defun window-current-scroll-bars (&optional window)
-  "Return the current scroll bar settings for WINDOW.
+  "Return the current scroll bar types for WINDOW.
 WINDOW must be a live window and defaults to the selected one.
 
 The return value is a cons cell (VERTICAL . HORIZONTAL) where
 VERTICAL specifies the current location of the vertical scroll
-bars (`left', `right', or nil), and HORIZONTAL specifies the
-current location of the horizontal scroll bars (`top', `bottom',
-or nil).
+bar (`left', `right' or nil), and HORIZONTAL specifies the
+current location of the horizontal scroll bar (`bottom' or nil).
 
 Unlike `window-scroll-bars', this function reports the scroll bar
 type actually used, once frame defaults and `scroll-bar-mode' are
 taken into account."
   (setq window (window-normalize-window window t))
-  (let ((vert (nth 2 (window-scroll-bars window)))
-       (hor nil))
-    (when (or (eq vert t) (eq hor t))
-      (let ((fcsb (frame-current-scroll-bars (window-frame window))))
-       (if (eq vert t)
-           (setq vert (car fcsb)))
-       (if (eq hor t)
-           (setq hor (cdr fcsb)))))
-    (cons vert hor)))
+  (let ((vertical (nth 2 (window-scroll-bars window)))
+       (horizontal (nth 5 (window-scroll-bars window)))
+       (inherited (frame-current-scroll-bars (window-frame window))))
+    (when (eq vertical t)
+      (setq vertical (car inherited)))
+    (when (eq horizontal t)
+      (setq horizontal (cdr inherited)))
+    (cons vertical (and horizontal 'bottom))))
 
 (defun walk-windows (fun &optional minibuf all-frames)
   "Cycle through all live windows, calling FUN for each one.
@@ -2956,6 +3018,28 @@ routines."
         pixel-delta
        (/ pixel-delta (frame-char-height frame)))))
 
+(defun window--sanitize-window-sizes (frame horizontal)
+  "Assert that all windows on FRAME are large enough.
+If necessary and possible, make sure that every window on frame
+FRAME has its minimum height.  Optional argument HORIZONTAL
+non-nil means to make sure that every window on frame FRAME has
+its minimum width.  The minimum height/width of a window is the
+respective value returned by `window-min-size' for that window.
+
+Return t if all windows were resized appropriately.  Return nil
+if at least one window could not be resized as requested, which
+may happen when the FRAME is not large enough to accommodate it."
+  (let ((value t))
+    (walk-window-tree
+     (lambda (window)
+       (let  ((delta (- (window-min-size window horizontal nil t)
+                       (window-size window horizontal t))))
+        (when (> delta 0)
+          (if (window-resizable-p window delta horizontal nil t)
+              (window-resize window delta horizontal nil t)
+            (setq value nil))))))
+    value))
+
 (defun adjust-window-trailing-edge (window delta &optional horizontal pixelwise)
   "Move WINDOW's bottom edge by DELTA lines.
 Optional argument HORIZONTAL non-nil means move WINDOW's right
@@ -4213,20 +4297,6 @@ showing BUFFER-OR-NAME."
        ;; If a window doesn't show BUFFER, unrecord BUFFER in it.
        (unrecord-window-buffer window buffer)))))
 \f
-;;; Splitting windows.
-(defun window-split-min-size (&optional horizontal pixelwise)
-  "Return minimum height of any window when splitting windows.
-Optional argument HORIZONTAL non-nil means return minimum width."
-  (cond
-   (pixelwise
-    (if horizontal
-       (window-min-pixel-width)
-      (window-min-pixel-height)))
-   (horizontal
-    (max window-min-width window-safe-min-width))
-   (t
-    (max window-min-height window-safe-min-height))))
-
 (defun split-window (&optional window size side pixelwise)
   "Make a new window adjacent to WINDOW.
 WINDOW must be a valid window and defaults to the selected one.
@@ -4290,6 +4360,9 @@ frame.  The selected window is not changed by this function."
         (pixel-size
          (when (numberp size)
            (window--size-to-pixel window size horizontal pixelwise t)))
+        (divider-width (if horizontal
+                           (frame-right-divider-width frame)
+                         (frame-bottom-divider-width frame)))
         atom-root)
     (window--check frame)
     (catch 'done
@@ -4311,12 +4384,7 @@ frame.  The selected window is not changed by this function."
        ;; side window, throw an error unless `window-combination-resize'
        ;; equals 'side.
        ((and (not (eq window-combination-resize 'side))
-            (or (window-parameter window 'window-side)
-                (and (window-child window)
-                     (or (window-parameter
-                          (window-child window) 'window-side)
-                         (window-parameter
-                          (window-last-child window) 'window-side)))))
+            (window--side-window-p window))
        (error "Cannot split side window or parent of side window"))
        ;; If `window-combination-resize' is 'side and window has a side
        ;; window sibling, bind `window-combination-limit' to t.
@@ -4391,19 +4459,14 @@ frame.  The selected window is not changed by this function."
          (cond
           (resize
            ;; SIZE unspecified, resizing.
-           (when (and (not (window-sizable-p
-                            parent (- new-pixel-size) horizontal nil t))
-                      ;; Try again with minimum split size.
-                      (setq new-pixel-size
-                            (max new-pixel-size
-                                 (window-split-min-size horizontal t)))
-                      (not (window-sizable-p
-                            parent (- new-pixel-size) horizontal nil t)))
-             (error "Window %s too small for splitting 1" parent)))
-          ((> (+ new-pixel-size (window-min-size window horizontal nil t))
+           (unless (window-sizable-p
+                    parent (- new-pixel-size divider-width) horizontal nil t)
+             (error "Window %s too small for splitting (1)" parent)))
+          ((> (+ new-pixel-size divider-width
+                 (window-min-size window horizontal nil t))
               old-pixel-size)
            ;; SIZE unspecified, no resizing.
-           (error "Window %s too small for splitting 2" window))))
+           (error "Window %s too small for splitting (2)" window))))
         ((and (>= pixel-size 0)
               (or (>= pixel-size old-pixel-size)
                   (< new-pixel-size
@@ -4411,19 +4474,19 @@ frame.  The selected window is not changed by this function."
          ;; SIZE specified as new size of old window.  If the new size
          ;; is larger than the old size or the size of the new window
          ;; would be less than the safe minimum, signal an error.
-         (error "Window %s too small for splitting 3" window))
+         (error "Window %s too small for splitting (3)" window))
         (resize
          ;; SIZE specified, resizing.
          (unless (window-sizable-p
-                  parent (- new-pixel-size) horizontal nil t)
+                  parent (- new-pixel-size divider-width) horizontal nil t)
            ;; If we cannot resize the parent give up.
-           (error "Window %s too small for splitting 4" parent)))
+           (error "Window %s too small for splitting (4)" parent)))
         ((or (< new-pixel-size
                 (window-safe-min-pixel-size window horizontal))
              (< (- old-pixel-size new-pixel-size)
                 (window-safe-min-pixel-size window horizontal)))
          ;; SIZE specification violates minimum size restrictions.
-         (error "Window %s too small for splitting 5" window)))
+         (error "Window %s too small for splitting (5)" window)))
 
        (window--resize-reset frame horizontal)
 
@@ -4494,6 +4557,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)
+
          (run-window-configuration-change-hook frame)
          (run-window-scroll-functions new)
          (window--check frame)
@@ -5065,7 +5131,7 @@ value can be also stored on disk and read back in a new session."
                (let ((scroll-bars (cdr (assq 'scroll-bars state))))
                  (set-window-scroll-bars
                   window (car scroll-bars) (nth 2 scroll-bars)
-                  (nth 3 scroll-bars)))
+                  (or (nth 3 scroll-bars) 0) (nth 5 scroll-bars)))
                (set-window-vscroll window (cdr (assq 'vscroll state)))
                ;; Adjust vertically.
                (if (memq window-size-fixed '(t height))
@@ -5733,7 +5799,7 @@ hold:
   wide as `split-width-threshold'.
 - When WINDOW is split evenly, the emanating windows are at least
   `window-min-width' or two (whichever is larger) columns wide."
-  (when (window-live-p window)
+  (when (and (window-live-p window) (not (window--side-window-p window)))
     (with-current-buffer (window-buffer window)
       (if horizontal
          ;; A window can be split horizontally when its width is not
@@ -5989,6 +6055,8 @@ The actual non-nil value of this variable will be copied to the
           (const display-buffer-pop-up-window)
           (const display-buffer-same-window)
           (const display-buffer-pop-up-frame)
+          (const display-buffer-below-selected)
+          (const display-buffer-at-bottom)
           (const display-buffer-in-previous-window)
           (const display-buffer-use-some-window)
           (function :tag "Other function"))
@@ -6398,13 +6466,26 @@ the selected one."
 
 (defun display-buffer-at-bottom (buffer alist)
   "Try displaying BUFFER in a window at the bottom of the selected frame.
-This either splits the window at the bottom of the frame or the
-frame's root window, or reuses an existing window at the bottom
-of the selected frame."
-  (let (bottom-window window)
+This either reuses such a window provided it shows BUFFER
+already, splits a window at the bottom of the frame or the
+frame's root window, or reuses some window at the bottom of the
+selected frame."
+  (let (bottom-window bottom-window-shows-buffer window)
     (walk-window-tree
-     (lambda (window) (setq bottom-window window)) nil nil 'nomini)
-    (or (and (not (frame-parameter nil 'unsplittable))
+     (lambda (window)
+       (cond
+       ((window-in-direction 'below window))
+       ((and (not bottom-window-shows-buffer)
+             (eq buffer (window-buffer window)))
+        (setq bottom-window-shows-buffer t)
+        (setq bottom-window window))
+       ((not bottom-window)
+        (setq bottom-window window)))
+       nil nil 'nomini))
+    (or (and bottom-window-shows-buffer
+            (window--display-buffer
+             buffer bottom-window 'reuse alist display-buffer-mark-dedicated))
+     (and (not (frame-parameter nil 'unsplittable))
             (let (split-width-threshold)
               (setq window (window--try-to-split-window bottom-window alist)))
             (window--display-buffer
@@ -7089,7 +7170,10 @@ FRAME."
             (value (window-text-pixel-size
                     nil t t workarea-width workarea-height t))
             (width (+ (car value) (window-right-divider-width)))
-            (height (+ (cdr value) (window-bottom-divider-width))))
+            (height
+             (+ (cdr value)
+                (window-bottom-divider-width)
+                (window-scroll-bar-height))))
        ;; Don't change height or width when the window's size is fixed
        ;; in either direction or ONLY forbids it.
        (cond
@@ -7248,6 +7332,7 @@ accessible position."
          ;; height.  Its width remains fixed.
          (setq height (+ (cdr (window-text-pixel-size
                                nil nil t nil (frame-pixel-height) t))
+                         (window-scroll-bar-height window)
                          (window-bottom-divider-width)))
          ;; Round height.
          (unless pixelwise