From d1273ad3170514bc28460b32886a6b4d7615742b Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sun, 27 Nov 2022 22:21:10 -0800 Subject: [PATCH] Make 'server-stop-automatically' into a defcustom * lisp/server.el (server-stop-automatically): Convert the variable to a defcustom. Remove the function. (server-stop-automatically--timer): New variable. (server-apply-stop-automatically): New function. (server-stop, server-start): Call 'server-apply-stop-automatically'. (server-save-buffers-kill-terminal): Adjust 'server-stop-automatically' conditional. (server-stop-automatically--handle-delete-frame) (server-stop-automatically--maybe-kill-emacs): Update docstrings. * doc/emacs/misc.texi (Emacs Server): Update documentation. --- doc/emacs/misc.texi | 13 +++---- lisp/server.el | 89 +++++++++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 29c0bed19c..e3c013acb1 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -1808,26 +1808,25 @@ Emacs Server emacs --daemon=foo @end example -@findex server-stop-automatically +@vindex server-stop-automatically The Emacs server can optionally be stopped automatically when -certain conditions are met. To do this, call the function -@code{server-stop-automatically} in your init file (@pxref{Init -File}), with one of the following arguments: +certain conditions are met. To do this, set the option +@code{server-stop-automatically} to one of the following values: @itemize @item -With the argument @code{empty}, the server is stopped when it has no +With the value @code{empty}, the server is stopped when it has no clients, no unsaved file-visiting buffers and no running processes anymore. @item -With the argument @code{delete-frame}, when the last client frame is +With the value @code{delete-frame}, when the last client frame is being closed, you are asked whether each unsaved file-visiting buffer must be saved and each unfinished process can be stopped, and if so, the server is stopped. @item -With the argument @code{kill-terminal}, when the last client frame is +With the value @code{kill-terminal}, when the last client frame is being closed with @kbd{C-x C-c} (@code{save-buffers-kill-terminal}), you are asked whether each unsaved file-visiting buffer must be saved and each unfinished process can be stopped, and if so, the server is diff --git a/lisp/server.el b/lisp/server.el index 1b027f88ce..dac07dfa35 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -273,6 +273,11 @@ server-client-instructions :version "28.1" :type 'boolean) +(defvar server-stop-automatically) ; Defined below to avoid recursive load. + +(defvar server-stop-automatically--timer nil + "The timer object for `server-stop-automatically--maybe-kill-emacs'.") + ;; We do not use `temporary-file-directory' here, because emacsclient ;; does not read the init file. (defvar server-socket-dir @@ -636,7 +641,8 @@ server-stop (setq stopped-p t server-process nil server-mode nil - global-minor-modes (delq 'server-mode global-minor-modes))) + global-minor-modes (delq 'server-mode global-minor-modes)) + (server-apply-stop-automatically)) (unwind-protect ;; Delete the socket files made by previous server ;; invocations. @@ -757,6 +763,7 @@ server-start (list :family 'local :service server-file :plist '(:authenticated t))))) + (server-apply-stop-automatically) (unless server-process (error "Could not start server process")) (server-log "Started server") (process-put server-process :server-file server-file) @@ -1769,9 +1776,6 @@ server-switch-buffer (when server-raise-frame (select-frame-set-input-focus (window-frame))))) -(defvar server-stop-automatically nil - "Internal status variable for `server-stop-automatically'.") - ;;;###autoload (defun server-save-buffers-kill-terminal (arg) ;; Called from save-buffers-kill-terminal in files.el. @@ -1780,7 +1784,8 @@ server-save-buffers-kill-terminal If emacsclient was started with a list of filenames to edit, then only these files will be asked to be saved." - (if server-stop-automatically + (if (and (daemonp) + (memq server-stop-automatically '(kill-terminal delete-frame)) (server-stop-automatically--handle-delete-frame (selected-frame)) (let ((proc (frame-parameter nil 'client))) (cond ((eq proc 'nowait) @@ -1805,7 +1810,7 @@ server-save-buffers-kill-terminal (t (error "Invalid client frame")))))) (defun server-stop-automatically--handle-delete-frame (frame) - "Handle deletion of FRAME when `server-stop-automatically' is used." + "Handle deletion of FRAME when `server-stop-automatically' is `delete-frame'." (when server-stop-automatically (if (if (and (processp (frame-parameter frame 'client)) (eq this-command 'save-buffers-kill-terminal)) @@ -1828,7 +1833,7 @@ server-stop-automatically--handle-delete-frame (delete-frame frame))))) (defun server-stop-automatically--maybe-kill-emacs () - "Handle closing of Emacs daemon when `server-stop-automatically' is used." + "Handle closing of Emacs daemon when `server-stop-automatically' is `empty'." (unless (cdr (frame-list)) (when (and (not (memq t (mapcar (lambda (b) @@ -1842,41 +1847,61 @@ server-stop-automatically--maybe-kill-emacs (process-list))))) (kill-emacs)))) -;;;###autoload -(defun server-stop-automatically (arg) - "Automatically stop server as specified by ARG. - -If ARG is the symbol `empty', stop the server when it has no +(defun server-apply-stop-automatically () + "Apply the current value of `server-stop-automatically'. +This function adds or removes the necessary helpers to manage +stopping the Emacs server automatically, depending on the whether +the server is running or not. This function only applies when +running Emacs as a daemon." + (when (daemonp) + (let (empty-timer-p delete-frame-p) + (when server-process + (pcase server-stop-automatically + ('empty (setq empty-timer-p t)) + ('delete-frame (setq delete-frame-p t)))) + ;; Start or stop the timer. + (if empty-timer-p + (unless server-stop-automatically--timer + (setq server-stop-automatically--timer + (run-with-timer + 10 2 + #'server-stop-automatically--maybe-kill-emacs))) + (when server-stop-automatically--timer + (cancel-timer server-stop-automatically--timer) + (setq server-stop-automatically--timer nil))) + ;; Add or remove the delete-frame hook. + (if delete-frame-p + (add-hook 'delete-frame-functions + #'server-stop-automatically--handle-delete-frame) + (remove-hook 'delete-frame-functions + #'server-stop-automatically--handle-delete-frame))))) + +(defcustom server-stop-automatically nil + "If non-nil, stop the server under the requested conditions. + +If this is the symbol `empty', stop the server when it has no remaining clients, no remaining unsaved file-visiting buffers, and no running processes with a `query-on-exit' flag. -If ARG is the symbol `delete-frame', ask the user when the last +If this is the symbol `delete-frame', ask the user when the last frame is deleted whether each unsaved file-visiting buffer must be saved and each running process with a `query-on-exit' flag can be stopped, and if so, stop the server itself. -If ARG is the symbol `kill-terminal', ask the user when the +If this is the symbol `kill-terminal', ask the user when the terminal is killed with \\[save-buffers-kill-terminal] \ whether each unsaved file-visiting buffer must be saved and each running process with a `query-on-exit' -flag can be stopped, and if so, stop the server itself. - -Any other value of ARG will cause this function to signal an error. - -This function is meant to be called from the user init file." - (when (daemonp) - (setq server-stop-automatically arg) - (cond - ((eq arg 'empty) - (setq server-stop-automatically nil) - (run-with-timer 10 2 - #'server-stop-automatically--maybe-kill-emacs)) - ((eq arg 'delete-frame) - (add-hook 'delete-frame-functions - #'server-stop-automatically--handle-delete-frame)) - ((eq arg 'kill-terminal)) - (t - (error "Unexpected argument"))))) +flag can be stopped, and if so, stop the server itself." + :type '(choice + (const :tag "Never" nil) + (const :tag "When empty" empty) + (const :tag "When killing last terminal" kill-terminal) + (const :tag "When killing last terminal or frame" delete-frame)) + :set (lambda (symbol value) + (set-default symbol value) + (server-apply-stop-automatically)) + :version "29.1") (define-key ctl-x-map "#" 'server-edit) -- 2.25.1