mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-21 06:55:39 +00:00
Fix two issues with 'window-deletable-p'
* lisp/window.el (window-deletable-functions): Clarify doc-string. (window-deletable-p): Handle check whether WINDOW's frame can be deleted via new function 'frame-deletable-p' (a comparison with the frame returned by 'next-frame' fails in too many cases). Do not try to run 'window-deletable-functions' in WINDOW's buffer when WINDOW is internal. * lisp/frame.el (frame-deletable-p): New function. * doc/lispref/frames.texi (Deleting Frames): Describe new function 'frame-deletable-p'. * etc/NEWS: Mention 'frame-deletable-p'.
This commit is contained in:
parent
0b7f649614
commit
bd647f3614
@ -2760,6 +2760,43 @@ With the prefix argument @var{iconify}, the frames are iconified rather
|
||||
than deleted.
|
||||
@end deffn
|
||||
|
||||
The following function checks whether a frame can be safely deleted. It
|
||||
is useful to avoid that a subsequent call of @code{delete-frame} throws
|
||||
an error.
|
||||
|
||||
@defun frame-deletable-p &optional frame
|
||||
This function returns non-@code{nil} if the frame specified by
|
||||
@var{frame} can be safely deleted. @var{frame} must be a live frame and
|
||||
defaults to the selected frame.
|
||||
|
||||
A frame cannot be safely deleted in the following cases:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
It is the only visible or iconified frame (@pxref{Visibility of
|
||||
Frames}).
|
||||
|
||||
@item
|
||||
It hosts the active minibuffer window and minibuffer windows do not
|
||||
follow the selected frame (@pxref{Basic Minibuffer,,, emacs}).
|
||||
|
||||
@item
|
||||
All other visible or iconified frames are either child frames
|
||||
(@pxref{Child Frames}) or have a non-@code{nil} @code{delete-before}
|
||||
parameter.
|
||||
|
||||
@item
|
||||
The frame or one of its descendants hosts the minibuffer window of a
|
||||
frame that is not a descendant of the frame (@pxref{Child Frames}).
|
||||
@end itemize
|
||||
|
||||
These conditions cover most cases where @code{delete-frame} might fail
|
||||
when called from top-level. They do not catch some special cases like,
|
||||
for example, deleting a frame during a drag-and-drop operation
|
||||
(@pxref{Drag and Drop}). In any such case, it will be better to wrap
|
||||
the @code{delete-frame} call in a @code{condition-case} form.
|
||||
@end defun
|
||||
|
||||
|
||||
@node Finding All Frames
|
||||
@section Finding All Frames
|
||||
|
11
etc/NEWS
11
etc/NEWS
@ -65,8 +65,8 @@ window used already has a 'quit-restore' parameter. Its presence gives
|
||||
operations more intuitively.
|
||||
|
||||
+++
|
||||
*** 'quit-restore-window' now handles the values 'killing' and 'burying'
|
||||
for its BURY-OR-KILL argument just like 'kill' and 'bury' but assumes
|
||||
*** 'quit-restore-window' handles new values for BURY-OR-KILL argument.
|
||||
The values 'killing' and 'burying' are like 'kill' and 'bury' but assume
|
||||
that the actual killing or burying of the buffer is done by the caller.
|
||||
|
||||
+++
|
||||
@ -74,6 +74,13 @@ that the actual killing or burying of the buffer is done by the caller.
|
||||
With this option set, 'quit-restore-window' will delete its window more
|
||||
aggressively rather than switching to some other buffer in it.
|
||||
|
||||
** Frames
|
||||
|
||||
+++
|
||||
*** New function 'frame-deletable-p'.
|
||||
Calling this function before 'delete-frame' is useful to avoid that the
|
||||
latter throws an error when the argument frame cannot be deleted.
|
||||
|
||||
** Tab Bars and Tab Lines
|
||||
|
||||
---
|
||||
|
@ -115,6 +115,74 @@ appended when the minibuffer frame is created."
|
||||
(sexp :tag "Value")))
|
||||
:group 'frames)
|
||||
|
||||
(defun frame-deletable-p (&optional frame)
|
||||
"Return non-nil if specified FRAME can be safely deleted.
|
||||
FRAME must be a live frame and defaults to the selected frame.
|
||||
|
||||
FRAME cannot be safely deleted in the following cases:
|
||||
|
||||
- FRAME is the only visible or iconified frame.
|
||||
|
||||
- FRAME hosts the active minibuffer window that does not follow the
|
||||
selected frame.
|
||||
|
||||
- All other visible or iconified frames are either child frames or have
|
||||
a non-nil `delete-before' parameter.
|
||||
|
||||
- FRAME or one of its descendants hosts the minibuffer window of a frame
|
||||
that is not a descendant of FRAME.
|
||||
|
||||
This covers most cases where `delete-frame' might fail when called from
|
||||
top-level. It does not catch some special cases like, for example,
|
||||
deleting a frame during a drag-and-drop operation. In any such case, it
|
||||
will be better to wrap the `delete-frame' call in a `condition-case'
|
||||
form."
|
||||
(setq frame (window-normalize-frame frame))
|
||||
(let ((active-minibuffer-window (active-minibuffer-window))
|
||||
deletable)
|
||||
(catch 'deletable
|
||||
(when (and active-minibuffer-window
|
||||
(eq (window-frame active-minibuffer-window) frame)
|
||||
(not (eq (default-toplevel-value
|
||||
'minibuffer-follows-selected-frame)
|
||||
t)))
|
||||
(setq deletable nil)
|
||||
(throw 'deletable nil))
|
||||
|
||||
(let ((frames (delq frame (frame-list))))
|
||||
(dolist (other frames)
|
||||
;; A suitable "other" frame must be either visible or
|
||||
;; iconified. Child frames and frames with a non-nil
|
||||
;; 'delete-before' parameter do not qualify as other frame -
|
||||
;; either of these will depend on a "suitable" frame found in
|
||||
;; this loop.
|
||||
(unless (or (frame-parent other)
|
||||
(frame-parameter other 'delete-before)
|
||||
(not (frame-visible-p other)))
|
||||
(setq deletable t))
|
||||
|
||||
;; Some frame not descending from FRAME may use the minibuffer
|
||||
;; window of FRAME or the minibuffer window of a frame
|
||||
;; descending from FRAME.
|
||||
(when (let* ((minibuffer-window (minibuffer-window other))
|
||||
(minibuffer-frame
|
||||
(and minibuffer-window
|
||||
(window-frame minibuffer-window))))
|
||||
(and minibuffer-frame
|
||||
;; If the other frame is a descendant of
|
||||
;; FRAME, it will be deleted together with
|
||||
;; FRAME ...
|
||||
(not (frame-ancestor-p frame other))
|
||||
;; ... but otherwise the other frame must
|
||||
;; neither use FRAME nor any descendant of
|
||||
;; it as minibuffer frame.
|
||||
(or (eq minibuffer-frame frame)
|
||||
(frame-ancestor-p frame minibuffer-frame))))
|
||||
(setq deletable nil)
|
||||
(throw 'deletable nil))))
|
||||
|
||||
deletable)))
|
||||
|
||||
(defun handle-delete-frame (event)
|
||||
"Handle delete-frame events from the X server."
|
||||
(interactive "e")
|
||||
|
@ -4109,8 +4109,8 @@ and no others."
|
||||
The value should be a list of functions that take two arguments. The
|
||||
first argument is the window about to be deleted. The second argument
|
||||
if non-nil, means that the window is the only window on its frame and
|
||||
should be deleted together with its frame. The window's buffer is
|
||||
current when running this hook.
|
||||
should be deleted together with its frame. If the window is live, its
|
||||
buffer is current when running this hook.
|
||||
|
||||
If any of these functions returns nil, the window will not be deleted
|
||||
and another buffer will be shown in it. This hook is run implicitly by
|
||||
@ -4147,23 +4147,13 @@ returns nil."
|
||||
;; WINDOW's frame can be deleted only if there are other frames
|
||||
;; on the same terminal, and it does not contain the active
|
||||
;; minibuffer.
|
||||
(unless (or (eq frame (next-frame frame 0))
|
||||
;; We can delete our frame only if no other frame
|
||||
;; currently uses our minibuffer window.
|
||||
(catch 'other
|
||||
(dolist (other (frame-list))
|
||||
(when (and (not (eq other frame))
|
||||
(eq (window-frame (minibuffer-window other))
|
||||
frame))
|
||||
(throw 'other t))))
|
||||
(let ((minibuf (active-minibuffer-window)))
|
||||
(and minibuf (eq frame (window-frame minibuf))
|
||||
(not (eq (default-toplevel-value
|
||||
'minibuffer-follows-selected-frame)
|
||||
t))))
|
||||
(unless (or (not (frame-deletable-p (window-frame window)))
|
||||
(or no-run
|
||||
(not (with-current-buffer (window-buffer window)
|
||||
(run-hook-with-args-until-failure
|
||||
(if (window-live-p window)
|
||||
(not (with-current-buffer (window-buffer window)
|
||||
(run-hook-with-args-until-failure
|
||||
'window-deletable-functions window t)))
|
||||
(not (run-hook-with-args-until-failure
|
||||
'window-deletable-functions window t)))))
|
||||
'frame))
|
||||
((window-minibuffer-p window)
|
||||
@ -4173,7 +4163,10 @@ returns nil."
|
||||
((and (or ignore-window-parameters
|
||||
(not (eq window (window-main-window frame))))
|
||||
(or no-run
|
||||
(with-current-buffer (window-buffer window)
|
||||
(if (window-live-p window)
|
||||
(with-current-buffer (window-buffer window)
|
||||
(run-hook-with-args-until-failure
|
||||
'window-deletable-functions window nil))
|
||||
(run-hook-with-args-until-failure
|
||||
'window-deletable-functions window nil))))
|
||||
;; Otherwise, WINDOW can be deleted unless it is the main window
|
||||
|
Loading…
Reference in New Issue
Block a user