I normally start Emacs in daemon mode and reload my last session with the desktop package. This causes whichever file desktop-read open last to remain visited in a buffer which is selected in the window which is selected in the “dummy” frame created for the daemon. As far as Emacs is concerned, this file is visible in a frame. But as far as I'm concerned, it's not.

I could fix all my code to skip the daemon's frame… if I could identify it. But it would be easier to just make the daemon frame visit a buffer whose visibility I don't particularly care about, like *Messages* or ​ *Minibuf-0.

What can I put in my init file to

  • identify whether Emacs was started in daemon mode;
  • identify the frame corresponding to the daemon;
  • make this frame visit a harmless buffer, or kill it (what can go wrong if I do that), or otherwise not let it continue “showing” some interesting buffer?

Test by running emacs --daemon -q -l foo.emacs where foo.emacs is

;; -*-emacs-lisp-*-
(setq server-name "foo")
;; Simulate loading a desktop session
(find-file "~/.emacs")
;; Test code
(defun foo ()
  (let* ((buffer (find-buffer-visiting "~/.emacs"))
         (window (get-buffer-window buffer t)))
    (if (interactive-p) (message "%S" window) window)))
;; Here goes the code I want

then I want emacsclient -s foo -e '(foo)' to return nil.

1 Answer 1


Immediately after starting Emacs, the daemon frame is the last one in the frame list. It has a single window which shows the last visited file.

(set-window-buffer (car (window-list (car (last (frame-list))))) "*Messages*")

In my use case, which is loading a desktop session, I need to do this after loading the session. I do this through a one-time hook.

(when (and (fboundp 'daemonp) (daemonp))
  (defun my-desktop-after-read-hook-set-window-buffer ()
    "Make the last frame in the frame list visit *Messages*.
This is intended for use after the first call to `desktop-read' in a daemon
Emacs. In this situation, the (sole) window in the daemon frame ends up
visiting the last buffer that was restored. Since this buffer is visited in
a window, some automation makes that window pop up (which has no actual
effect) instead of displaying the buffer in the current window or a new one."
    (set-window-buffer (car (window-list (car (last (frame-list)))))
    (remove-hook 'desktop-after-read-hook 'my-desktop-after-read-hook-set-window-buffer))
  (add-hook 'desktop-after-read-hook 'my-desktop-after-read-hook-set-window-buffer))

Ugly, but it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.