(use-package server :defer t :preface (defun user--server-save-buffers-kill-terminal (arg) "Offer to save each buffer, then kill the current client. With ARG non-nil, silently save all file-visiting buffers, then kill. If emacsclient was started with a list of filenames to edit, then only these files will be asked to be saved. If Emacs was started as a daemon and this is the last client connected to it, this will call `save-buffers-kill-emacs'." (let ((proc (frame-parameter nil 'client))) (cond ((eq proc 'nowait) ;; Nowait frames have no client buffer list. (if (if (daemonp) (cddr (frame-list)) (cdr (frame-list))) ;; If there's another (non-daemon) frame, only delete this ;; frame. FIXME: It would be nice to delete any other frames ;; created by this frame (as when killing the terminal of an ;; ordinary client below), but we can't distinguish separate ;; groups of nowait frames currently. (progn (save-some-buffers arg) (delete-frame)) ;; If we're the last frame standing, kill Emacs. (save-buffers-kill-emacs arg))) ((processp proc) (if (seq-some (lambda (frame) (let ((p (frame-parameter frame 'client))) (unless (and (daemonp) (null p)) (not (equal proc p))))) (frame-list)) ;; If there's a frame not from this client, only delete the ;; client. (let ((buffers (process-get proc 'buffers))) (save-some-buffers arg (if buffers ;; Only files from emacsclient file list. (lambda () (memq (current-buffer) buffers)) ;; No emacsclient file list: don't override ;; `save-some-buffers-default-predicate' (unless ;; ARG is non-nil), since we're not killing ;; Emacs (unlike `save-buffers-kill-emacs'). (and arg t))) (server-delete-client proc)) ;; If all frames are from this client, kill Emacs. (save-buffers-kill-emacs arg))) (t (error "Invalid client frame"))))) (defun user--server-kill-emacs-query-function () "Ask before exiting Emacs if it has live clients. If Emacs was started as a daemon and the only live client is the current frame's client, don't bother asking." (let ((ignored-proc (and (daemonp) (frame-parameter nil 'client)))) (or (not (seq-some (lambda (proc) (unless (eq ignored-proc proc) (seq-some #'buffer-live-p (process-get proc 'buffers)))) server-clients)) (yes-or-no-p "This Emacs session has clients; exit anyway? ")))) (defun user--handle-delete-frame (frame) "When deleting the last non-daemon frame, kill Emacs. \(To be used from `delete-frame-functions'.)" (when (and (daemonp) ;; Check that the frame is a client frame. ;; Note: `server-delete-client' sets `client' to nil before ;; calling `delete-frame', but that's good, since we want to call ;; `save-buffers-kill-emacs' before all that anyway. (frame-parameter frame 'client) (null (cddr (frame-list)))) (save-buffers-kill-emacs))) :config (advice-add #'server-save-buffers-kill-terminal :override #'user--server-save-buffers-kill-terminal) (advice-add #'server-kill-emacs-query-function :override #'user--server-kill-emacs-query-function) (add-hook 'delete-frame-functions #'user--handle-delete-frame))