From 0626d5aba518a6d22ffacd7a1e3f4c70d7248e5f Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Mon, 11 Jun 2018 16:54:23 -0700 Subject: [PATCH] Add after-delete-frame-functions Instead of working around the behavior delete-frame-functions, just add an after-delete-frame-functions hook. * doc/lispref/frames.texi (Deleting Frames): Document `after-delete-frame-functions'. * etc/NEWS: Mention `after-delete-frame-functions'. * lisp/frame.el (blink-cursor--should-blink): (blink-cursor--rescan-frames, blink-frame-mode): Get rid of the ugly ignored-frame parameter and switch from `delete-frame-functions' to `after-delete-frame-functions'. * src/frame.c (syms_of_frame): New variable `after-delete-frame-functions'. (delete_frame): Use it. --- doc/lispref/frames.texi | 5 ++++- etc/NEWS | 6 ++++++ lisp/frame.el | 27 ++++++++++----------------- src/frame.c | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index 3a97ec01384..5e8b5b46d5d 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -2530,6 +2530,7 @@ it. @deffn Command delete-frame &optional frame force @vindex delete-frame-functions +@vindex after-delete-frame-functions This function deletes the frame @var{frame}. The argument @var{frame} must specify a live frame (see below) and defaults to the selected frame. @@ -2541,7 +2542,9 @@ performed recursively; so this step makes sure that no other frames with @var{frame} as their ancestor will exist. Then, unless @var{frame} specifies a tooltip, this function runs the hook @code{delete-frame-functions} (each function getting one argument, -@var{frame}) before actually killing the frame. +@var{frame}) before actually killing the frame. After actually killing +the frame and removing the frame from the frame list, @code{delete-frame} +runs @code{after-delete-frame-functions}. Note that a frame cannot be deleted as long as its minibuffer serves as surrogate minibuffer for another frame (@pxref{Minibuffers and Frames}). diff --git a/etc/NEWS b/etc/NEWS index 7b14b9f8960..402dcb13c7f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -582,6 +582,12 @@ manual for more details. * Lisp Changes in Emacs 27.1 ++++ +** New hook `after-delete-frame-functions'. Works like + `delete-frame-functions', but runs after the frame to be deleted + has been made dead and removed from the frame list, simplifying + some kinds of code. + +++ ** New focus state inspection interface: `focus-in-hook' and `focus-out-hook' are marked obsolete. Instead, attach to diff --git a/lisp/frame.el b/lisp/frame.el index a0e7b35a138..38f785901e7 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -2416,40 +2416,33 @@ frame receives focus." (cancel-timer blink-cursor-idle-timer) (setq blink-cursor-idle-timer nil))) -(defun blink-cursor--should-blink (&optional ignored-frame) +(defun blink-cursor--should-blink () "Determine whether we should be blinking. -Returns whether we have any focused non-TTY frame. IGNORED-FRAME -is a frame to ignore during the scan, used when we want to ignore -a frame about to be deleted." +Returns whether we have any focused non-TTY frame." (and blink-cursor-mode (let ((frame-list (frame-list)) (any-graphical-focused nil)) (while frame-list (let ((frame (pop frame-list))) - (when (and (not (eq frame ignored-frame)) - (display-graphic-p frame) - (frame-focus-state frame)) + (when (and (display-graphic-p frame) (frame-focus-state frame)) (setf any-graphical-focused t) (setf frame-list nil)))) any-graphical-focused))) -(defun blink-cursor-check (&optional ignored-frame) +(defun blink-cursor-check () "Check if cursor blinking shall be restarted. This is done when a frame gets focus. Blink timers may be stopped by `blink-cursor-suspend'. Internally calls `blink-cursor--should-blink' and returns its result." - (let ((should-blink (blink-cursor--should-blink ignored-frame))) + (let ((should-blink (blink-cursor--should-blink))) (when (and should-blink (not blink-cursor-idle-timer)) (remove-hook 'post-command-hook 'blink-cursor-check) (blink-cursor--start-idle-timer)) should-blink)) -(defun blink-cursor--rescan-frames (&optional ignored-frame) - "Called when the set of focused frames changes or when we -delete a frame. Re-check whether we want to enable blinking. -IGNORED-FRAME is there so we ignore a frame about to be deleted -when we're called under via `delete-frame-functions'." - (unless (blink-cursor-check ignored-frame) +(defun blink-cursor--rescan-frames (&optional _ign) + "Called when the set of focused frames changes or when we delete a frame." + (unless (blink-cursor-check) (blink-cursor-suspend))) (define-minor-mode blink-cursor-mode @@ -2474,11 +2467,11 @@ terminals, cursor blinking is controlled by the terminal." :group 'cursor :global t (blink-cursor-suspend) - (remove-hook 'delete-frame-functions #'blink-cursor--rescan-frames) + (remove-hook 'after-delete-frame-functions #'blink-cursor--rescan-frames) (remove-function after-focus-change-function #'blink-cursor--rescan-frames) (when blink-cursor-mode (add-function :after after-focus-change-function #'blink-cursor--rescan-frames) - (add-hook 'delete-frame-functions #'blink-cursor--rescan-frames) + (add-hook 'after-delete-frame-functions #'blink-cursor--rescan-frames) (blink-cursor--start-idle-timer))) diff --git a/src/frame.c b/src/frame.c index bf0269292d6..d477c1acc3f 100644 --- a/src/frame.c +++ b/src/frame.c @@ -2161,6 +2161,16 @@ delete_frame (Lisp_Object frame, Lisp_Object force) if (!is_tooltip_frame) update_mode_lines = 15; + /* Now run the post-deletion hooks. */ + if (NILP (Vrun_hooks) || is_tooltip_frame) + ; + else if (EQ (force, Qnoelisp)) + pending_funcalls + = Fcons (list3 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame), + pending_funcalls); + else + safe_call2 (Qrun_hook_with_args, Qafter_delete_frame_functions, frame); + return Qnil; } @@ -5897,6 +5907,14 @@ recursively). */); Vdelete_frame_functions = Qnil; DEFSYM (Qdelete_frame_functions, "delete-frame-functions"); + DEFVAR_LISP ("after-delete-frame-functions", + Vafter_delete_frame_functions, + doc: /* Functions run after deleting a frame. +The functions are run with one arg, the frame that was deleted and +which is now dead. */); + Vafter_delete_frame_functions = Qnil; + DEFSYM (Qafter_delete_frame_functions, "after-delete-frame-functions"); + DEFVAR_LISP ("menu-bar-mode", Vmenu_bar_mode, doc: /* Non-nil if Menu-Bar mode is enabled. See the command `menu-bar-mode' for a description of this minor mode. -- 2.39.2