commit 2f63dab3ee566f5794fac4139a8f8b8b9e250a00 (HEAD, refs/remotes/origin/master) Author: Roland Winkler Date: Fri Jan 10 22:34:16 2025 -0600 In bibtex.el, fix widgets for customization types (bug#74409) * lisp/textmodes/bibtex.el (bibtex-field-list, bibtex-entry-alist) (bibtex-field-alist): Fix widgets for customization types (bug#74409). diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index 5e79ccc6e55..601331cbce2 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -283,6 +283,7 @@ If parsing fails, try to set this variable to nil." (define-widget 'bibtex-field-list 'lazy "Format of fields of entries in `bibtex-BibTeX-entry-alist' and friends." + :tag "Field list" :type '(group (string :tag "Field") (option (choice :tag "Comment" :value nil (const nil) string)) @@ -293,7 +294,9 @@ If parsing fails, try to set this variable to nil." (define-widget 'bibtex-entry-alist 'lazy "Format of `bibtex-BibTeX-entry-alist' and friends." + :tag "Entry alist" :type '(repeat + :format "\n%v" (choice (group :tag "Alias" (string :tag "Entry type") (string :tag "Documentation") @@ -860,8 +863,11 @@ Use this, e.g., for custom fields, see Sec. 2.2.4 of the biblatex manual." (define-widget 'bibtex-field-alist 'lazy "Format of `bibtex-BibTeX-field-alist' and friends." - :type '(repeat (group (string :tag "Field type") - (string :tag "Comment")))) + :tag "Field alist" + :type '(repeat + :format "\n%v" + (group (string :tag "Field type") + (string :tag "Comment")))) (defcustom bibtex-BibTeX-field-alist '(("author" "Author1 [and Author2 ...] [and others]") commit f51129b4fc3f50a20856d0d9bd1ac5b61daf08da Author: Roland Winkler Date: Fri Jan 10 21:48:54 2025 -0600 Improve some docstrings in bibtex.el * lisp/textmodes/bibtex.el: (bibtex-BibTeX-entry-alist) (bibtex-biblatex-entry-alist, bibtex-BibTeX-field-alist): Improve docstrings. (bibtex-biblatex-entry-alist): Minor fix. diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el index a8f803f7313..5e79ccc6e55 100644 --- a/lisp/textmodes/bibtex.el +++ b/lisp/textmodes/bibtex.el @@ -448,11 +448,11 @@ If parsing fails, try to set this variable to nil." ("howpublished" "The way in which the work was published") ("month") ("year") ("note")))) "Alist of BibTeX entry types and their associated fields. -Elements are lists of the form (ENTRY DOC REQUIRED CROSSREF OPTIONAL) +Elements are lists (ENTRY DOC REQUIRED CROSSREF OPTIONAL) or (ENTRY DOC REF-ENTRY). ENTRY is the type of a BibTeX entry. -DOC is a brief doc string used for documentation. If nil, ENTRY is used. +DOC is a brief doc string used for documentation. If nil use ENTRY. REF-ENTRY is another entry type, where ENTRY becomes an alias that inherits the definition of REF-ENTRY. @@ -743,7 +743,7 @@ See also `bibtex-BibTeX-aux-entry-alist' which takes precedence." ("PhdThesis" "PhD Thesis" (("author") ("title" "Title of the PhD thesis") - ("institution") + ("institution" nil nil 6) ("school" nil nil -6) ("date" nil nil 1) ("year" nil nil -1)) nil (("subtitle") ("titleaddon") ("language") ("note") @@ -875,9 +875,9 @@ Use this, e.g., for custom fields, see Sec. 2.2.4 of the biblatex manual." ("crossref" "Reference key of the cross-referenced entry") ("key" "Used as label with certain BibTeX styles")) "Alist of BibTeX fields. -Each element is a list of the form (FIELD COMMENT). COMMENT is -a comment used with `bibtex-print-help-message' as a default -if `bibtex-BibTeX-entry-alist' does not define a comment for FIELD." +Each element is a list (FIELD COMMENT). COMMENT is a comment used with +`bibtex-print-help-message' as a default if `bibtex-BibTeX-entry-alist' +does not define a comment for FIELD." :group 'bibtex :version "31.1" :type 'bibtex-field-alist) commit e024bd1d1f904b271d337e85ef730afcc87e73d2 Author: john muhl Date: Sun Jan 5 10:24:02 2025 -0600 ; Fix typo (Bug#75480) diff --git a/lisp/mpc.el b/lisp/mpc.el index 00155bfabc8..e25983e48c9 100644 --- a/lisp/mpc.el +++ b/lisp/mpc.el @@ -2838,7 +2838,7 @@ will be used. See `mpc-format' for the definition of FORMAT-SPEC." (defcustom mpc-notifications-body '("%{Artist}" "%{AlbumArtist}" "Unknown Artist") - "List of FORMAT-SPEC used in the notification body. + "List of FORMAT-SPECs used in the notification body. The first element in the list that expands to a non-empty string will be used. See `mpc-format' for the definition of FORMAT-SPEC." commit 8e9ad92a140e89c3e29dd7ab148534289e7769db Author: Robert Pluim Date: Mon Jan 6 16:38:07 2025 +0100 Protect Vframe_list updating from interruptions * src/frame.c (delete_frame): When deleting the frame from Vframe_list, block input, since input can arrive whilst we're running lisp (Bug#74902). diff --git a/src/frame.c b/src/frame.c index 7c07100e944..146ecb226a4 100644 --- a/src/frame.c +++ b/src/frame.c @@ -2497,7 +2497,9 @@ delete_frame (Lisp_Object frame, Lisp_Object force) delete_all_child_windows (f->root_window); fset_root_window (f, Qnil); + block_input (); Vframe_list = Fdelq (frame, Vframe_list); + unblock_input (); SET_FRAME_VISIBLE (f, false); /* Allow the vector of menu bar contents to be freed in the next commit d1e6379d6ab6148b0c93369daf51f7d6b10a3c9a Author: Pranshu Sharma Date: Fri Jan 10 16:07:30 2025 +0100 Add new file window-x.el * lisp/window-x.el: New file. * etc/NEWS: Mention new commands to modify window layout. diff --git a/etc/NEWS b/etc/NEWS index 5d108b5b9a1..5d193ffcb9e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -153,6 +153,16 @@ the "*Completions*" buffer is hidden. ** Windows +*** New functions to modify window layout. +Several functions to modify the window layout have been added: +'rotate-window-layout-clockwise' +'rotate-window-layout-anticlockwise' +'flip-window-layout-vertically' +'flip-window-layout-horizontally' +'transpose-window-layout' +'rotate-windows' +'rotate-windows-back' + +++ *** New hook 'window-deletable-functions'. This abnormal hook gives its client a way to save a window from getting diff --git a/lisp/window-x.el b/lisp/window-x.el new file mode 100644 index 00000000000..d6c1851ddeb --- /dev/null +++ b/lisp/window-x.el @@ -0,0 +1,336 @@ +;;; window-x.el --- extended window commands -*- lexical-binding: t; -*- + +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; Author: Pranshu Sharma +;; Martin Rudalics +;; Maintainer: emacs-devel@gnu.org +;; Keywords: files +;; Package: emacs + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; This file defines additional infrequently used window commands that +;; should not be in window.el to not make the dumped image bigger. + +;;; Code: + +(defun window-tree-normal-sizes (window &optional next) + "Return normal sizes of all windows rooted at WINDOW. +A list of the form (SPLIT-TYPE PARENT-WIN PARENT-WIN-HEIGHT +PARENT-WIN-WIDTH W1 W2 ...) is returned. SPLIT-TYPE is non-nil if +PARENT-WIN is split horizontally. PARENT-WIN is the internal window. +PARENT-WIN-HEIGHT and PARENT-WIN-WIDTH are the normal heights of +PARENT-WIN. Wn is a list of the form (WINDOW HEIGHT WIDTH) where HEIGHT +and WIDTH are the normal height and width of the window." + (let (list) + (while window + (setq list + (cons + (cond + ((window-top-child window) + (append + (list t window + (window-normal-size window nil) + (window-normal-size window t)) + (window-tree-normal-sizes (window-top-child window) t))) + ((window-left-child window) + (append + (list nil window + (window-normal-size window nil) + (window-normal-size window t)) + (window-tree-normal-sizes (window-left-child window) t))) + (t (list window + (window-normal-size window nil) + (window-normal-size window t)))) + list)) + (setq window (when next (window-next-sibling window)))) + (nreverse list))) + +(defun window--window-to-transpose (frame-or-window) + "Return the window to be acted upon by `window--transpose'. +If FRAME-OR-WINDOW is a window return FRAME-OR-WINDOW. If +FRAME-OR-WINDOW is a frame, return FRAME-OR-WINDOW's main window. If +FRAME-OR-WINDOW is nil, than the frames main window wil be returned. If +FRAME-OR-WINDOW is non-nil, and not a frame or a window or a number, +than the return value will be the parent window of the selected window." + (cond + ((windowp frame-or-window) + frame-or-window) + ((or (framep frame-or-window) (not frame-or-window)) + (window-main-window frame-or-window)) + (frame-or-window + (window-parent)))) + +(defun rotate-window-layout-anticlockwise (&optional frame-or-window) + "Rotate windows of FRAME-OR-WINDOW anticlockwise by 90 degrees. +Transform the layout of windows such that a window on top becomes a +window on the right, a window on the right moves to the bottom, a window +on the bottom moves to the left and a window on the left becomes one on +the top. + +If FRAME-OR-WINDOW is nil, rotate the main window of the selected +frame. If FRAME-OR-WINDOW specifies a live frame, rotate the main +window of that frame. If FRAME-OR-WINDOW specifies a parent window, +rotate that window. In any other case and interactively with a prefix +argument rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (window--transpose window '(right . above) nil))) + +(defun rotate-window-layout-clockwise (&optional frame-or-window) + "Rotate windows of FRAME-OR-WINDOW clockwise by 90 degrees. +Transform the layout of windows such that a window on top becomes a +window on the right, a window on the right moves to the bottom, a +window on the bottom moves to the left and a window on the left becomes +one on the top. + +If FRAME-OR-WINDOW is nil, rotate the main window of the selected frame. +If FRAME-OR-WINDOW specifies a live frame, rotate the main window of +that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that +window. In any other case and interactively with a prefix argument +rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (window--transpose window '(left . below) nil))) + +(defun flip-window-layout-horizontally (&optional frame-or-window) + "Horizontally flip windows of FRAME-OR-WINDOW. +Flip the window layout so that the window on the right becomes the +window on the left, and vice-versa. + +If FRAME-OR-WINDOW is nil, flip the main window of the selected frame. +If FRAME-OR-WINDOW specifies a live frame, rotate the main window of +that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that +window. In any other case and interactively with a prefix argument +rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (window--transpose window '(below . left) t))) + +(defun flip-window-layout-vertically (&optional frame-or-window) + "Verticlly flip windows of FRAME-OR-WINDOW. +Flip the window layout so that the top window becomes the bottom window +and vice-versa. + +If FRAME-OR-WINDOW is nil, flip the main window of the selected frame. +If FRAME-OR-WINDOW specifies a live frame, rotate the main window of +that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that +window. In any other case and interactively with a prefix argument +rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (window--transpose window '(above . right) t))) + +(defun transpose-window-layout (&optional frame-or-window) + "Transpose windows of FRAME-OR-WINDOW. +Make the windows on FRAME-OR-WINDOW so that every horizontal split +becomes a vertical split, and vice versa. This is equivalent to +diagonally flipping. + +If FRAME-OR-WINDOW is nil, transpose the main window of the selected frame. +If FRAME-OR-WINDOW specifies a live frame, rotate the main window of +that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that +window. In any other case and interactively with a prefix argument +rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (window--transpose window '(right . below) nil))) + +(defun window--depmap(fun ls) + "Map FUN across all nodes of list LS." + (if (consp ls) + (cons + (if (consp (car ls)) + (window--depmap fun (car ls)) + (funcall fun (car ls))) + (window--depmap fun (cdr ls))) + (funcall fun ls))) + +(defun rotate-windows-back(&optional frame-or-window) + "Move windows into locations of their predecessors in cyclic ordering. + +If FRAME-OR-WINDOW is nil, rotate the main window of the selected frame. +If FRAME-OR-WINDOW specifies a live frame, rotate the main window of +that frame. If FRAME-OR-WINDOW specifies a parent window, rotate that +window. In any other case and interactively with a prefix argument +rotate the parent window of the selected window." + (interactive "P") + (rotate-windows frame-or-window t)) + +(defun rotate-windows (&optional frame-or-window reverse) + "Move windows into locations of their forerunners in cyclic ordering. + +Else if FRAME-OR-WINDOW is nil, rotate the main window of the +selected frame. If FRAME-OR-WINDOW specifies a live frame, rotate the +main window of that frame. If FRAME-OR-WINDOW specifies a parent +window, rotate that window. In any other case and interactively with a +prefix argument rotate the parent window of the selected window." + (interactive "P") + (let ((window (window--window-to-transpose frame-or-window))) + (if (or (not window) + (window-live-p window)) + (message "No windows to transpose") + (let* ((frame (window-frame window)) + (selected-window (frame-selected-window window)) + (win-tree (car (window-tree-normal-sizes window))) + (winls (seq-filter 'window-live-p (flatten-list win-tree))) + (rotated-ls (if reverse + (append (cdr winls) (list (car winls))) + (append (last winls) winls))) + (other-window-arg (if reverse 1 -1)) + (first-window (car rotated-ls)) + (new-win-tree (window--depmap + (lambda (x) + (if (window-live-p x) + (pop rotated-ls) + x)) + win-tree))) + (if (or (seq-some 'window-atom-root winls) + (seq-some 'window-fixed-size-p winls)) + (message "This does not work with fixed size or atom windows.") + (progn + ;; All child windows need to be recursively deleted. + (delete-other-windows-internal first-window window) + ;; (delete-dups atom-windows) + (window--transpose-1 new-win-tree first-window '(below . right) t nil) + (set-frame-selected-window frame selected-window) + (other-window other-window-arg) + (while (not (memq (selected-window) winls)) + (other-window other-window-arg)))))))) + +(defun window--transpose (window conf no-resize) + "Rearrange windows of WINDOW recursively. +CONF should be a cons cell: (HORIZONTAL-SPLIT . VERTICAL-SPLIT) where +HORIZONTAL-SPLIT will be used as the third argument of `split-window' +when splitting a window that was previously horizontally split, and +VERTICAL-SPLIT as third argument of `split-window' for a window that was +previously vertically split. If NO-RESIZE is nil, the SIDE argument of +the window-split is converted from vertical to horizontal or vice versa, +with the same proportion of the total split." + (if (or (not window) + (window-live-p window)) + (message "No windows to transpose") + (let* ((frame (window-frame window)) + (first-window window) + (selected-window (frame-selected-window window)) + (win-tree (car (window-tree-normal-sizes window))) + (win-list (seq-filter 'window-live-p (flatten-list win-tree))) + (atom-windows + (remq nil (mapcar 'window-atom-root + win-list)))) + (if (and (not (eq (car atom-windows) window)) + (or no-resize + (and (not atom-windows) + (not (seq-some 'window-fixed-size-p win-list))))) + (progn + (delete-dups atom-windows) + (while (not (window-live-p first-window)) + (setq first-window (window-child first-window))) + (delete-other-windows-internal first-window window) + (window--transpose-1 win-tree first-window conf no-resize atom-windows) + ;; Go back to previously selected window. + (set-frame-selected-window frame selected-window) + (mapc 'window-make-atom atom-windows)) + (message "This does not work with fixed size or atom windows."))))) + +(defun window--transpose-1 (subtree cwin conf no-resize atom-windows) + "Subroutine of `window--transpose'. +SUBTREE must be in the format of the result of +`window-tree-normal-sizes'. CWIN is the current window through which +the window splits are made. ATOM-WINDOWS is a list of internal atom +windows. The CONF and NO-RESIZE arguments are the same as the +ones in `window--transpose'." + ;; `flen' is max size the window could be converted to the opposite + ;; of the given split type. + (let ((parent-window-is-set t) + (flen (if (funcall (if no-resize 'not 'identity) + (car subtree)) + (float (window-pixel-width cwin)) + (float (window-pixel-height cwin))))) + (mapc + (pcase-lambda (`(,window . ,size)) + (prog1 + (let* ((split-size (- (round (* flen size)))) + (split-type + (funcall (if (car subtree) 'car 'cdr) conf)) + (return-win + (if (listp window) + ;; `window' is a window subtree. + ;; `first-child' is a live window that is an descended of window + (let* ((first-child window) + ;; If the window being split is atomic + (is-atom + ;; cadr will return the internal parent window + (memq (cadr first-child) atom-windows))) + ;; (caar (cddddr first-child)) is the first window in the + ;; list if there is a live window. + (while (not (windowp (caar (cddddr first-child)))) + (setq first-child (car (cddddr first-child)))) + (window--transpose-1 + window + (let ((window-combination-limit parent-window-is-set)) + (split-window + cwin + split-size + split-type + t + (if window-combination-limit + (cons (caar (cddddr first-child)) (cadr subtree)) + (caar (cddddr first-child))))) + (if is-atom + '(nil . t) + conf) + no-resize + atom-windows)) + ;; `window' is a window. + (split-window + cwin + split-size + split-type t + ;; We need to set parent window if it hasn't been set + ;; already. + (if parent-window-is-set + (cons window (cadr subtree)) + window))))) + (when (eq window-combination-limit t) + (set-window-combination-limit (cadr subtree) nil)) + return-win) + (setq parent-window-is-set nil))) + (mapcar + (lambda (e) + (pcase-let* ((`(,window . ,window-size-info) + (if (windowp (car e)) + (cons (car e) e) + (cons e (cdr e))))) + (cons window + ;; The respective size of the window. + (if (car subtree) + (cadr window-size-info) + (caddr window-size-info))))) + ;; We need to ingore first 5 elements of window list, we ignore + ;; window split type, sizes and the first window (it's + ;; implicitly created). We just have a list of windows. + (nreverse (cdr (cddddr subtree))))) + ;; (caar (cddddr subtree)) is the first child window of subtree. + (unless (windowp (caar (cddddr subtree))) + (let ((is-atom (memq (cadr (cadr (cddddr subtree))) atom-windows))) + (window--transpose-1 (car (cddddr subtree)) cwin (if is-atom '(nil . t) conf) + no-resize atom-windows))))) + +;;; window-x.el ends here commit 4a8c885dfab87e85edd0897725a242a48f88436b Author: Eli Zaretskii Date: Fri Jan 10 17:03:16 2025 +0200 ; Fix recently added documentation * doc/lispref/windows.texi (Splitting Windows): Fix punctuation. (Resurrecting Windows): Fix typo. * doc/lispref/elisp.texi (Top): Add the new node to @detailmenu. diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index cc5762e37e5..adec6d847ea 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -1075,6 +1075,7 @@ Windows * Deleting Windows:: Deleting a window gives its space to other windows. * Recombining Windows:: Preserving the frame layout when splitting and deleting windows. +* Resurrecting Windows:: Restoring deleted windows. * Cyclic Window Ordering:: Moving around the existing windows. * Buffers and Windows:: Each window displays the contents of a buffer. * Switching Buffers:: Higher-level functions for switching to a buffer. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 10254db2068..cb406c4e670 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -1427,7 +1427,7 @@ window. If non-@code{nil}, @var{refer} can be either a window or a cons cell of two windows. If @var{refer} is a cons cell, its @sc{car} has to specify a deleted, -former live window - a window that has shown a buffer before - on the +former live window -- a window that has shown a buffer before -- on the same frame as @var{window}. That buffer must be still live. The @sc{cdr} has to specify a deleted window that was, before its deletion, a parent window on the same frame as @var{window}. In this case, rather @@ -1439,10 +1439,10 @@ immediately before @var{refer}'s @sc{car} was deleted the last time. Decorations and parameters remain unaltered from their values before @var{refer}'s @sc{car} and @sc{cdr} were deleted. -Alternatively, @var{refer} may specify a deleted, former live window - a -window that has shown a buffer before - on the same frame as +Alternatively, @var{refer} may specify a deleted, former live window -- a +window that has shown a buffer before -- on the same frame as @var{window}. That buffer must be still live. In this case, this -function do not make a new window but rather makes @var{refer} live +function does not make a new window but rather makes @var{refer} live again and inserts it into the window tree at the position and with the sizes the new window would have been given. Buffer, start and point positions of @var{refer} are set to the values they had immediately @@ -2108,7 +2108,8 @@ After a window has been deleted (@pxref{Deleting Windows}) it cannot be used any more by functions that require a valid window as their argument even if some Lisp variable still references that window. When the last reference to a window has ceased to exist, the window's Lisp object will -be eventually recycled by the garbage collector. +be eventually recycled by the garbage collector (@pxref{Garbage +Collection}). There are two ways to resurrect a deleted window whose object has not been yet recycled by the collector: The first is to keep a reference to @@ -2189,7 +2190,7 @@ returned by @code{window-prev-sibling} and @code{window-next-sibling} of the window and its sibling. The following code passes both, the new window on the right and its -parent, via the @var{refer} argument to @code{split-window}: instead. +parent, via the @var{refer} argument to @code{split-window} instead. @example @group commit c2dbe029104d75866813c1d0c10c0b2173bb85c7 Author: Eli Zaretskii Date: Fri Jan 10 16:51:27 2025 +0200 ; * doc/lispref/windows.texi (Resurrecting Windows): Fix typo. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 6e5726bde4d..10254db2068 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -2099,7 +2099,7 @@ distribute its space proportionally among the two remaining live windows. -@node Resurrecting windows +@node Resurrecting Windows @section Resurrecting Windows @cindex resurrecting deleted windows @cindex restoring deleted windows commit 7f286e7d83665526929dea3f7180f3a5ba8ef14e Author: Martin Rudalics Date: Fri Jan 10 09:24:20 2025 +0100 Have 'split-window' optionally resurrect deleted windows * src/window.c (Fwindow_old_buffer): Handle deleted window as argument. (make_parent_window): Remove function. (Fsplit_window_internal): New argument REFER for resurrecting deleted windows. Incorporate functionality of defunct make_parent_window. (Fdelete_window_internal, delete_all_child_windows): Store any deleted window's buffer in the window's old_buffer slot. (window_dead_windows_table): Make it a 'value' type hash table so the sequence number cannot affect its weakness. * lisp/window.el (split-window): New argument REFER. * doc/lispref/windows.texi (Resurrecting Windows): New section. (Splitting Windows): Explain new argument REFER. (Window Hooks): Rewrite description of 'window-old-buffer'. * etc/NEWS: Mention new REFER argument for 'split-window'. diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index cea859a4493..6e5726bde4d 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -22,6 +22,7 @@ is displayed in windows. * Deleting Windows:: Removing a window from its frame. * Recombining Windows:: Preserving the frame layout when splitting and deleting windows. +* Resurrecting Windows:: Restoring deleted windows. * Cyclic Window Ordering:: Moving around the existing windows. * Buffers and Windows:: Each window displays the contents of a buffer. * Switching Buffers:: Higher-level functions for switching to a buffer. @@ -1357,7 +1358,7 @@ the sense that these functions may fail to split them as described here. Examples of such windows are side windows (@pxref{Side Windows}) and atomic windows (@pxref{Atomic Windows}). -@defun split-window &optional window size side pixelwise +@defun split-window &optional window size side pixelwise refer This function creates a new live window next to the window @var{window}. If @var{window} is omitted or @code{nil}, it defaults to the selected window. That window is split, and reduced in @@ -1401,14 +1402,62 @@ the right of @var{window}. If @var{side} is @code{left}, the new window is placed on the left of @var{window}. In both these cases, @var{size} specifies a total window width, in columns. +As a rule, if @var{window} already forms a combination (@pxref{Windows +and Frames}) that matches @var{side} (a horizontal combination matches +@var{side} if it is @code{left} or @code{right}, a vertical combination +matches @var{side} if it is @code{above} or @code{below}) and +@code{window-combination-limit} (@pxref{Recombining Windows}) is +@code{nil}, this function reuses @var{window}'s parent in the window +tree as parent of the new window. + +However, if @var{window} is in a combination that does not match +@var{side} or if @code{window-combination-limit} is non-@code{nil}, this +function makes a new parent window that replaces @var{window} in the +window tree and makes @var{window} and the new window its sole child +windows. This standard behavior can be overridden via the @var{refer} +argument. + The optional fourth argument @var{pixelwise}, if non-@code{nil}, means to interpret @var{size} in units of pixels, instead of lines and columns. -If @var{window} is a live window, the new window inherits various -properties from it, including margins and scroll bars. If -@var{window} is an internal window, the new window inherits the -properties of the window selected within @var{window}'s frame. +If the optional fifth argument @var{refer} is non-@code{nil}, it +specifies a reference window used for setting up properties of the new +window. If non-@code{nil}, @var{refer} can be either a window or a cons +cell of two windows. + +If @var{refer} is a cons cell, its @sc{car} has to specify a deleted, +former live window - a window that has shown a buffer before - on the +same frame as @var{window}. That buffer must be still live. The +@sc{cdr} has to specify a deleted window that was, before its deletion, +a parent window on the same frame as @var{window}. In this case, rather +then making new windows, this function replaces @var{window} with the +@sc{cdr} of @var{refer} in the window tree and makes @var{window} and +@var{refer}'s @sc{car} its new child windows. Buffer, start and point +positions of @var{refer}'s @sc{car} are set to the values they had +immediately before @var{refer}'s @sc{car} was deleted the last time. +Decorations and parameters remain unaltered from their values before +@var{refer}'s @sc{car} and @sc{cdr} were deleted. + +Alternatively, @var{refer} may specify a deleted, former live window - a +window that has shown a buffer before - on the same frame as +@var{window}. That buffer must be still live. In this case, this +function do not make a new window but rather makes @var{refer} live +again and inserts it into the window tree at the position and with the +sizes the new window would have been given. Buffer, start and point +positions of @var{refer} are set to the values they had immediately +before @var{refer} was deleted the last time. Decorations and +parameters remain unaltered from their values before @var{refer} was +deleted. The parent of @var{refer} is then determined as if it were a +window created anew. + +In any other case, @var{refer} must specify a live window. Then the new +window will inherit properties like buffer, start and point positions +and some decorations from @var{refer}. If @var{refer} is @code{nil} or +omitted, then if @var{window} is live, the new window inherits these +properties from @var{window}. If, however, @var{window} is an internal +window, the new window will inherit these properties from the window +selected on @var{window}'s frame. The behavior of this function may be altered by the window parameters of @var{window}, so long as the variable @@ -2050,6 +2099,131 @@ distribute its space proportionally among the two remaining live windows. +@node Resurrecting windows +@section Resurrecting Windows +@cindex resurrecting deleted windows +@cindex restoring deleted windows + +After a window has been deleted (@pxref{Deleting Windows}) it cannot be +used any more by functions that require a valid window as their argument +even if some Lisp variable still references that window. When the last +reference to a window has ceased to exist, the window's Lisp object will +be eventually recycled by the garbage collector. + +There are two ways to resurrect a deleted window whose object has not +been yet recycled by the collector: The first is to keep a reference to +that window in a saved window configuration (@pxref{Window +Configurations}) and then call @code{set-window-configuration} with that +configuration as argument. The second one is to keep a reference to +that window in a variable or let-bind it and then use that reference as +@var{refer} argument in @code{split-window} (@pxref{Splitting Windows}). + +The major difference between these two is that +@code{set-window-configuration} restores the frame layout as it existed +before deleting the window. The @code{split-window} approach, on the +other hand, allows for arbitrary variations of the layout. + +Consider the following example starting with a frame containing a single +window showing the buffer @file{*scratch*}: + +@example +@group +(let* ((old (selected-window)) + (new (split-window old nil 'right)) + overlay) + (with-current-buffer (get-buffer-create "*Messages*") + (set-window-buffer new (current-buffer)) + (setq overlay (make-overlay (point-min) (point-max))) + (overlay-put overlay 'face 'highlight) + (overlay-put overlay 'window new) + (message "new %s parent %s" new (window-parent new)) + (sit-for 3)) + (delete-window new) + (setq new (split-window old nil 'left)) + (set-window-buffer new (get-buffer-create "*Messages*")) + (format "new %s parent %s" new (window-parent new))) +@end group +@end example + +When you run that code in @file{*scratch*} it will first split the +window showing @file{*scratch*} to display @file{*Messages*} in a new +window on the right. It also sets up an overlay with a window property +to highlight the text of @file{*Messages*} in the new window and +displays a message showing the new window and its parent in the window +tree. It then deletes the new window and resurrects it on the left of +the @file{*scratch*} window again displaying a message showing the new +window and its parent in the window tree. + +Note that both, new window and its parent have changed after moving the +@file{*Messages*} window to the left. Also, the highlighting disappears +because any properties set up for the new window on the right are lost +when the new window is re-created on the left. + +The following code uses the @var{refer} argument of @code{split-window} +instead. + +@example +@group +(let* ((old (selected-window)) + (new (split-window old nil 'right)) + overlay) + (with-current-buffer (get-buffer-create "*Messages*") + (set-window-buffer new (current-buffer)) + (setq overlay (make-overlay (point-min) (point-max))) + (overlay-put overlay 'face 'highlight) + (overlay-put overlay 'window new) + (message "new %s parent %s" new (window-parent new)) + (sit-for 3)) + (delete-window new) + (split-window old nil 'left nil new) + (format "new %s parent %s" new (window-parent new))) +@end group +@end example + +Note that all properties of the resurrected window like its decorations, +parameters as well as any overlays with a window property are preserved +as if that window had never been deleted. The only things that changed +are its position in the window tree and consequently the values returned +by @code{window-left-child} of its parent window as well as the values +returned by @code{window-prev-sibling} and @code{window-next-sibling} of +the window and its sibling. + +The following code passes both, the new window on the right and its +parent, via the @var{refer} argument to @code{split-window}: instead. + +@example +@group +(let* ((old (selected-window)) + (new (split-window old nil 'right)) + (parent (window-parent new)) + overlay) + (with-current-buffer (get-buffer-create "*Messages*") + (set-window-buffer new (current-buffer)) + (setq overlay (make-overlay (point-min) (point-max))) + (overlay-put overlay 'face 'highlight) + (overlay-put overlay 'window new) + (message "new %s parent %s" new (window-parent new)) + (sit-for 3)) + (delete-window new) + (split-window old nil 'left nil (cons new parent)) + (format "new %s parent %s" new (window-parent new))) +@end group +@end example + +Note that the parent window has been resurrected along with the new +window. + +Resurrecting dead windows is useful to preserve the identity of windows +in actions that are supposed to do that like moving windows around on a +frame or hiding them temporarily. Any properties of such a window like +its decorations, the buffer it has shown previously, that buffer's start +and point position in the window, the window's dedicated status or its +cursor type are left untouched and there's no need to recreate them from +scratch. For internal windows, the value of that window's combination +limit is preserved which means that the window can be recombined +(@pxref{Recombining Windows}) as before. + + @node Cyclic Window Ordering @section Cyclic Ordering of Windows @cindex cyclic ordering of windows @@ -7135,13 +7309,16 @@ live window as single, optional argument, defaulting to the selected window. @defun window-old-buffer &optional window -This function returns the buffer shown in @var{window} at the last -time window change functions were run for @var{window}'s frame. If it -returns @code{nil}, @var{window} has been created after that. If it -returns @code{t}, @var{window} was not shown at that time but has been -restored from a previously saved window configuration afterwards. -Otherwise, the return value is the buffer shown by @var{window} at -that time. +This function returns the buffer shown in @var{window} at the last time +window change functions were run for @var{window}'s frame. If it +returns @code{nil}, @var{window} is either an internal window or has +been created after that. If it returns @code{t}, @var{window} was not +shown at that time but has been restored from a previously saved window +configuration afterwards. Otherwise, the return value is the buffer +shown by @var{window} at that time. As a special case, if @var{window} +has been deleted, this function returns the last buffer @var{window} had +shown at that time. @var{window} can be any window and defaults to the +selected one. @end defun @defun window-old-pixel-width &optional window diff --git a/etc/NEWS b/etc/NEWS index fc762d01942..5d108b5b9a1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -164,6 +164,13 @@ deleted implicitly by functions like 'kill-buffer', 'bury-buffer' and This option has 'kill-buffer' call 'quit-restore-window' to handle the further destiny of any window showing the buffer to be killed. ++++ +*** 'split-window' can optionally resurrect deleted windows. +A new argument REFER of 'split-window' makes it possible to, instead of +making a new window object, reuse an existing, deleted one. This can be +used to preserve the identity of windows when swapping or transposing +them. + +++ *** New window parameter 'quit-restore-prev'. This parameter is set up by 'display-buffer' when it detects that the diff --git a/lisp/window.el b/lisp/window.el index ada5f1179a5..886128c7daa 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -5511,7 +5511,7 @@ PARENT divided by their number plus 1." (setq sibling (window-next-sibling sibling))) (/ size (1+ number)))) -(defun split-window (&optional window size side pixelwise) +(defun split-window (&optional window size side pixelwise refer) "Make a new window adjacent to WINDOW. WINDOW must be a valid window and defaults to the selected one. Return the new window which is always a live window. @@ -5542,23 +5542,63 @@ For compatibility reasons, SIDE `up' and `down' are interpreted as `above' and `below'. Any other non-nil value for SIDE is currently handled like t (or `right'). +As a rule, if WINDOW already forms a combination that matches the SIDE +parameter and `window-combination-limit' is nil, reuse WINDOW's parent +in the window tree as parent of the new window. If WINDOW is in a +combination that is orthogonal to the SIDE parameter or if +`window-combination-limit' is non-nil, make a new parent window that +replaces WINDOW in the window tree and make WINDOW and the new window +its sole child windows. This standard behavior can be overridden via +the REFER argument. + PIXELWISE, if non-nil, means to interpret SIZE pixelwise. +If the optional fifth argument REFER is non-nil, it specifies a +reference window used for setting up properties of the new window. +REFER can be either a window or a cons cell of two windows. + +If REFER is a cons cell, its car has to specify a deleted, former live +window - a window that has shown a buffer before - on the same frame as +WINDOW. That buffer must be still live. The cdr has to specify a +deleted window that was a parent window on the same frame as WINDOW +before it was deleted. In this case, rather then making new windows, +replace WINDOW with the cdr of REFER in the window tree and make WINDOW +and REFER's car its new child windows. Buffer, start and point +positions of REFER's car are set to the values they had immediately +before REFER's car was deleted the last time. Decorations and +parameters remain unaltered from their values before REFER's car and cdr +were deleted. + +Alternatively REFER may specify a deleted, former live window - a window +that has shown a buffer before - on the same frame as WINDOW. In this +case do not make a new window but rather make REFER live again and +insert it into the window tree at the position and with the sizes the +new window would have been given. Buffer, start and point positions of +REFER are set to the values they had immediately before REFER was +deleted the last time. Decorations and parameters remain unaltered from +their values before REFER was deleted. Throw an error if REFER's buffer +has been deleted after REFER itself was deleted. + +Otherwise REFER must specify a live window. In this case, the new +window will inherit properties like buffer, start and point position and +some decorations from REFER. If REFER is nil or omitted, then if WINDOW +is live, any such properties are inherited from WINDOW. If, however, +WINDOW is an internal window, the new window will inherit these +properties from the window selected on WINDOW's frame. + If the variable `ignore-window-parameters' is non-nil or the `split-window' parameter of WINDOW equals t, do not process any -parameters of WINDOW. Otherwise, if the `split-window' parameter -of WINDOW specifies a function, call that function with all three -arguments and return the value returned by that function. - -Otherwise, if WINDOW is part of an atomic window, \"split\" the -root of that atomic window. The new window does not become a -member of that atomic window. - -If WINDOW is live, properties of the new window like margins and -scrollbars are inherited from WINDOW. If WINDOW is an internal -window, these properties as well as the buffer displayed in the -new window are inherited from the window selected on WINDOW's -frame. The selected window is not changed by this function." +parameters of WINDOW. Otherwise, if the `split-window' parameter of +WINDOW specifies a function, call that function with the three first +arguments WINDOW, SIZE and SIDE and return the value returned by that +function. + +Otherwise, if WINDOW is part of an atomic window, \"split\" the root of +that atomic window. The new window does not become a member of that +atomic window. + +The selected window and the selected window on WINDOW's frame are not +changed by this function." (setq window (window-normalize-window window)) (let* ((side (cond ((not side) 'below) @@ -5598,14 +5638,14 @@ frame. The selected window is not changed by this function." ((and (window-parameter window 'window-atom) (setq atom-root (window-atom-root window)) (not (eq atom-root window))) - (throw 'done (split-window atom-root size side pixelwise))) + (throw 'done (split-window atom-root size side pixelwise refer))) ;; If WINDOW's frame has a side window and WINDOW specifies the ;; frame's root window, split the frame's main window instead ;; (Bug#73627). ((and (eq window (frame-root-window frame)) (window-with-parameter 'window-side nil frame)) (throw 'done (split-window (window-main-window frame) - size side pixelwise))) + size side pixelwise refer))) ;; If WINDOW is a side window or its first or last child is a ;; side window, throw an error unless `window-combination-resize' ;; equals 'side. @@ -5644,8 +5684,8 @@ frame. The selected window is not changed by this function." (window-combined-p window horizontal))) ;; 'old-pixel-size' is the current pixel size of WINDOW. (old-pixel-size (window-size window horizontal t)) - ;; 'new-size' is the specified or calculated size of the - ;; new window. + ;; 'new-pixel-size' is the specified or calculated size + ;; of the new window. new-pixel-size new-parent new-normal) (cond ((not pixel-size) @@ -5766,8 +5806,9 @@ frame. The selected window is not changed by this function." window (- (if new-parent 1.0 (window-normal-size window horizontal)) new-normal))) - (let* ((new (split-window-internal window new-pixel-size side new-normal))) - (window--pixel-to-total frame horizontal) + (let ((new (split-window-internal + window new-pixel-size side new-normal refer))) + (window--pixel-to-total frame horizontal) ;; Assign window-side parameters, if any. (cond ((eq window-combination-resize 'side) diff --git a/src/window.c b/src/window.c index 17bbe213e05..ff58eb12ee0 100644 --- a/src/window.c +++ b/src/window.c @@ -652,15 +652,16 @@ Return nil for an internal window or a deleted window. */) DEFUN ("window-old-buffer", Fwindow_old_buffer, Swindow_old_buffer, 0, 1, 0, doc: /* Return the old buffer displayed by WINDOW. -WINDOW must be a live window and defaults to the selected one. +WINDOW can be any window and defaults to the selected one. The return value is the buffer shown in WINDOW at the last time window -change functions were run. It is nil if WINDOW was created after -that. It is t if WINDOW has been restored from a window configuration -after that. */) +change functions were run or WINDOW is a former live window that was +deleted. It is nil if WINDOW was created after that. It is t if WINDOW +has been restored from a window configuration after that. It is always +nil if WINDOW is an internal window. */) (Lisp_Object window) { - struct window *w = decode_live_window (window); + struct window *w = decode_any_window (window); return (NILP (w->old_buffer) /* A new window. */ @@ -668,8 +669,8 @@ after that. */) : (w->change_stamp != WINDOW_XFRAME (w)->change_stamp) /* A window restored from a configuration. */ ? Qt - /* A window that was live the last time seen by window - change functions. */ + /* A window that was live the last time seen by window change + functions or was deleted. */ : w->old_buffer); } @@ -4524,45 +4525,6 @@ allocate_window (void) PVEC_WINDOW); } -/* Make new window, have it replace WINDOW in window-tree, and make - WINDOW its only vertical child (HORFLAG means make WINDOW its only - horizontal child). */ -static void -make_parent_window (Lisp_Object window, bool horflag) -{ - Lisp_Object parent; - register struct window *o, *p; - - o = XWINDOW (window); - p = allocate_window (); - memcpy ((char *) p + sizeof (union vectorlike_header), - (char *) o + sizeof (union vectorlike_header), - word_size * VECSIZE (struct window)); - /* P's buffer slot may change from nil to a buffer... */ - adjust_window_count (p, 1); - XSETWINDOW (parent, p); - - p->sequence_number = ++sequence_number; - - replace_window (window, parent, true); - - wset_next (o, Qnil); - wset_prev (o, Qnil); - wset_parent (o, parent); - /* ...but now P becomes an internal window. */ - wset_start (p, Qnil); - wset_pointm (p, Qnil); - wset_old_pointm (p, Qnil); - wset_buffer (p, Qnil); - wset_combination (p, horflag, window); - wset_combination_limit (p, Qnil); - /* Reset any previous and next buffers of p which have been installed - by the memcpy above. */ - wset_prev_buffers (p, Qnil); - wset_next_buffers (p, Qnil); - wset_window_parameters (p, Qnil); -} - /* Make new window from scratch. */ Lisp_Object make_window (void) @@ -5106,7 +5068,7 @@ resize_frame_windows (struct frame *f, int size, bool horflag) } -DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 4, 0, +DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0, doc: /* Split window OLD. Second argument PIXEL-SIZE specifies the number of pixels of the new window. It must be a positive integer. @@ -5121,32 +5083,33 @@ SIDE t (or `right') specifies that the new window shall be located on the right side of WINDOW. SIDE `left' means the new window shall be located on the left of WINDOW. In both cases PIXEL-SIZE specifies the width of the new window including space reserved for fringes and the -scrollbar or a divider column. +scroll bar or a divider column. Fourth argument NORMAL-SIZE specifies the normal size of the new window -according to the SIDE argument. +according to the SIDE argument. Optional fifth argument REFER is as for +'split-window'. The new pixel and normal sizes of all involved windows must have been set correctly. See the code of `split-window' for how this is done. */) - (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, Lisp_Object normal_size) -{ - /* OLD (*o) is the window we have to split. (*p) is either OLD's - parent window or an internal window we have to install as OLD's new - parent. REFERENCE (*r) must denote a live window, or is set to OLD - provided OLD is a leaf window, or to the frame's selected window. - NEW (*n) is the new window created with some parameters taken from - REFERENCE (*r). */ - Lisp_Object new, frame, reference; - struct window *o, *p, *n, *r, *c; - struct frame *f; + (Lisp_Object old, Lisp_Object pixel_size, Lisp_Object side, + Lisp_Object normal_size, Lisp_Object refer) +{ + /* OLD (*o) is the window to split. REFER (*r) is a reference window, + either an arbitrary live window or a former live, now deleted + window on the same frame as OLD. NEW (*n) is the new window + created anew or resurrected from REFER (*r), if specified. *p + refers either to OLD's parent window that will become NEW's parent + window too or to a new internal window that becomes OLD's and NEW's + new parent. */ + struct window *o = decode_valid_window (old); + Lisp_Object frame = WINDOW_FRAME (o); + struct frame *f = XFRAME (frame); + struct window *p, *n, *r, *c; bool horflag /* HORFLAG is true when we split side-by-side, false otherwise. */ = EQ (side, Qt) || EQ (side, Qleft) || EQ (side, Qright); - - CHECK_WINDOW (old); - o = XWINDOW (old); - frame = WINDOW_FRAME (o); - f = XFRAME (frame); + Lisp_Object new, parent = Qnil; + bool dead = false; CHECK_FIXNUM (pixel_size); EMACS_INT total_size @@ -5164,14 +5127,74 @@ set correctly. See the code of `split-window' for how this is done. */) ? WINDOW_VERTICAL_COMBINATION_P (XWINDOW (o->parent)) : WINDOW_HORIZONTAL_COMBINATION_P (XWINDOW (o->parent)))); - /* We need a live reference window to initialize some parameters. */ - if (WINDOW_LIVE_P (old)) - /* OLD is live, use it as reference window. */ - reference = old; + /* Set up reference window. */ + if (NILP (refer)) + { + if (WINDOW_LIVE_P (old)) + /* OLD is live, use it as reference window. */ + refer = old; + else + /* Use the frame's selected window as reference window. */ + refer = FRAME_SELECTED_WINDOW (f); + + r = XWINDOW (refer); + } + else if (CONSP (refer)) + { + /* If REFER is a cons, then its car must be a deleted, former live + window and its cdr must be a deleted former parent window. Set + PARENT to the cdr of REFER and REFER to its car. WINDOW and + REFER end up as the sole children of PARENT which replaces + WINDOW in the window tree. As a special case, if REFER's cdr + is t, reuse REFER's car's old parent as new parent provided it + is a deleted fromer parent window. */ + parent = Fcdr (refer); + refer = Fcar (refer); + r = decode_any_window (refer); + + if (!NILP (r->contents) || !BUFFERP (r->old_buffer)) + error ("REFER's car must specify a deleted, former live window"); + else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer))) + error ("The buffer formerly shown by REFER's car has been killed"); + else if (!EQ (r->frame, frame)) + error ("REFER's car must specify a window on same frame as WINDOW"); + + if (EQ (parent, Qt)) + /* If REFER's cdr is t, use the old parent of REFER's car as new + parent. */ + parent = r->parent; + + p = decode_any_window (parent); + + if (!NILP (p->contents) || BUFFERP (p->old_buffer)) + error ("REFER's cdr must specify a deleted, former parent window"); + else if (!EQ (p->frame, frame)) + error ("REFER's cdr must specify window on same frame as WINDOW"); + + dead = true; + } else - /* Use the frame's selected window as reference window. */ - reference = FRAME_SELECTED_WINDOW (f); - r = XWINDOW (reference); + { + r = decode_any_window (refer); + + if (NILP (r->contents)) + /* Presumably a deleted, former live window. Check whether its + contents can be used. */ + { + if (!BUFFERP (r->old_buffer)) + error ("REFER must specify a former live window (must have shown a buffer)"); + else if (!BUFFER_LIVE_P (XBUFFER (r->old_buffer))) + error ("The buffer formerly shown by REFER has been killed"); + else if (!EQ (r->frame, frame)) + error ("REFER must specify a window on same frame as WINDOW"); + + dead = true; + } + else if (!NILP (parent)) + error ("If REFER is a cons, its car must not specify a live window"); + else if (!WINDOW_LIVE_P (refer)) + error ("REFER is not a live window (does not show a buffer)"); + } /* The following bugs are caught by `split-window'. */ if (MINI_WINDOW_P (o)) @@ -5182,16 +5205,18 @@ set correctly. See the code of `split-window' for how this is done. */) /* `window-combination-resize' non-nil means try to resize OLD's siblings proportionally. */ { - p = XWINDOW (o->parent); + struct window *op = XWINDOW (o->parent); + /* Temporarily pretend we split the parent window. */ wset_new_pixel - (p, make_fixnum ((horflag ? p->pixel_width : p->pixel_height) + (op, make_fixnum ((horflag ? op->pixel_width : op->pixel_height) - XFIXNUM (pixel_size))); - if (!window_resize_check (p, horflag)) + if (!window_resize_check (op, horflag)) error ("Window sizes don't fit"); else /* Undo the temporary pretension. */ - wset_new_pixel (p, make_fixnum (horflag ? p->pixel_width : p->pixel_height)); + wset_new_pixel + (op, make_fixnum (horflag ? op->pixel_width : op->pixel_height)); } else { @@ -5211,8 +5236,24 @@ set correctly. See the code of `split-window' for how this is done. */) Lisp_Object new_normal = horflag ? o->normal_cols : o->normal_lines; - make_parent_window (old, horflag); - p = XWINDOW (o->parent); + if (NILP (parent)) + /* This is the crux of the old make_parent_window. */ + { + p = allocate_window (); + XSETWINDOW (parent, p); + p->sequence_number = ++sequence_number; + wset_frame (p, frame); + } + else + /* Pacify GCC. */ + p = XWINDOW (parent); + + replace_window (old, parent, true); + wset_next (o, Qnil); + wset_prev (o, Qnil); + wset_parent (o, parent); + wset_combination (p, horflag, old); + if (EQ (Vwindow_combination_limit, Qt)) /* Store t in the new parent's combination_limit slot to avoid that its children get merged into another window. */ @@ -5228,7 +5269,12 @@ set correctly. See the code of `split-window' for how this is done. */) p = XWINDOW (o->parent); fset_redisplay (f); - new = make_window (); + + if (dead) + new = refer; + else + new = make_window (); + n = XWINDOW (new); wset_frame (n, frame); wset_parent (n, o->parent); @@ -5255,16 +5301,19 @@ set correctly. See the code of `split-window' for how this is done. */) n->window_end_valid = false; n->last_cursor_vpos = 0; - /* Get special geometry settings from reference window. */ - n->left_margin_cols = r->left_margin_cols; - n->right_margin_cols = r->right_margin_cols; - n->left_fringe_width = r->left_fringe_width; - n->right_fringe_width = r->right_fringe_width; - n->fringes_outside_margins = r->fringes_outside_margins; - n->scroll_bar_width = r->scroll_bar_width; - n->scroll_bar_height = r->scroll_bar_height; - wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type); - wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type); + if (!dead) + { + /* Get special geometry settings from reference window. */ + n->left_margin_cols = r->left_margin_cols; + n->right_margin_cols = r->right_margin_cols; + n->left_fringe_width = r->left_fringe_width; + n->right_fringe_width = r->right_fringe_width; + n->fringes_outside_margins = r->fringes_outside_margins; + n->scroll_bar_width = r->scroll_bar_width; + n->scroll_bar_height = r->scroll_bar_height; + wset_vertical_scroll_bar_type (n, r->vertical_scroll_bar_type); + wset_horizontal_scroll_bar_type (n, r->horizontal_scroll_bar_type); + } /* Directly assign orthogonal coordinates and sizes. */ if (horflag) @@ -5293,6 +5342,7 @@ set correctly. See the code of `split-window' for how this is done. */) sum = sum + XFIXNUM (c->new_total); c = NILP (c->next) ? 0 : XWINDOW (c->next); } + wset_new_total (n, make_fixnum ((horflag ? p->total_cols : p->total_lines) @@ -5300,10 +5350,30 @@ set correctly. See the code of `split-window' for how this is done. */) wset_new_normal (n, normal_size); block_input (); + + if (dead) + { + /* Get dead window back its old buffer and markers. */ + wset_buffer (n, n->old_buffer); + set_marker_restricted + (n->start, make_fixnum (XMARKER (n->start)->charpos), n->contents); + set_marker_restricted + (n->pointm, make_fixnum (XMARKER (n->pointm)->charpos), n->contents); + set_marker_restricted + (n->old_pointm, make_fixnum (XMARKER (n->old_pointm)->charpos), + n->contents); + + Vwindow_list = Qnil; + /* Remove window from the table of dead windows. */ + Fremhash (make_fixnum (n->sequence_number), + window_dead_windows_table); + } + window_resize_apply (p, horflag); adjust_frame_glyphs (f); - /* Set buffer of NEW to buffer of reference window. */ + set_window_buffer (new, r->contents, true, true); + FRAME_WINDOW_CHANGE (f) = true; unblock_input (); @@ -5401,6 +5471,8 @@ Signal an error when WINDOW is the only window on its frame. */) } else { + /* Store WINDOW's buffer in old_buffer. */ + wset_old_buffer (w, w->contents); unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); unchain_marker (XMARKER (w->old_pointm)); @@ -7745,6 +7817,8 @@ delete_all_child_windows (Lisp_Object window) } else if (BUFFERP (w->contents)) { + /* Store WINDOW's buffer in old_buffer. */ + wset_old_buffer (w, w->contents); unshow_buffer (w); unchain_marker (XMARKER (w->pointm)); unchain_marker (XMARKER (w->old_pointm)); @@ -9097,12 +9171,9 @@ displayed after a scrolling operation to be somewhat inaccurate. */); doc: /* Hash table of dead windows. Each entry in this table maps a window number to a window object. Entries are added by `delete-window-internal' and are removed by the -garbage collector. - -This table is maintained by code in window.c and is made visible in -Elisp for testing purposes only. */); +garbage collector. */); window_dead_windows_table - = CALLN (Fmake_hash_table, QCweakness, Qt); + = CALLN (Fmake_hash_table, QCweakness, Qvalue); DEFVAR_BOOL ("window-auto-redraw-on-parameter-change", window_auto_redraw_on_parameter_change,