When I start emacs (emacs), and then eval (visible-frame-list), I get a list with one frame, the one that is visable. However if I start emacs as a daemon (emacs --daemon), and then eval (visible-frame-list) (emacsclient --eval '(visible-frame-list)'). I also have one frame, but as expected this is none visible.

This causes a problem, because after I do emacsclient -c I get a real frame, and (visible-frame-list) evaluates to two frames.

Why is this a problem? I have some emacs lisp code that does shuts down emacs when there are no-longer any frames, but it does not trigger because of this out by one error.

(defun intelligent-close ()
  "quit a frame the same way no matter what kind of frame you are on"
  (if (eq (car (visible-frame-list)) (selected-frame))
      ;;for parent/master frame...
      (if (> (length (visible-frame-list)) 1)
          ;;close a parent with children present
          (delete-frame (selected-frame))
        ;;close a parent with no children present
    ;;close a child frame
    (delete-frame (selected-frame))))

I could “fix it” by changing the 1 to a 2, but I suspect that this will cause it to get a false positive at some point in the future.

Can you help to:

  • get rid of this extra frame
  • be confident that my hack will always work
  • OR find another solution

A don't care which.

note If I do

emacs --daemon
emacsclient -c --no-wait
emacsclient --eval '(delete-frame (car (visible-frame-list)))'
emacsclient --eval '(visible-frame-list)'

Then I get the desired result (for this state).

  • You should be able to do this by adding your delete-frame stanza to server-mode-hook, but that doesn't get called when you enter server-mode via the daemon, which is arguably a bug in emacs. Or you can hack emacs to set the initial frame invisible, but that no doubt also has other effects.
    – rpluim
    Commented Sep 10, 2018 at 15:26

1 Answer 1


This extra frame is the terminal-frame. So you can check:

(defun intelligent-close ()
  "quit a frame the same way no matter what kind of frame you are on"
  (let ((frames (visible-frame-list)))
    (if (eq (car frames) (selected-frame))
        ;; For parent/master frame...
        (if (cdr frames)
            ;; Close a parent with children present.
              (delete-frame (selected-frame))
              (when (and (eq (cadr frames) terminal-frame)
                         (null (cddr frames)))
                ;; No frames left on this daemon: shut it down.
          ;; Close a parent with no children present.
      ;; Close a child frame.
      (delete-frame (selected-frame))))

This special frame is kept specifically so as to be able to keep the daemon running when there are no visible frames left (Emacs needs a live frame somewhere).

  • 1
    The end of your procedure is missing. Commented Sep 12, 2018 at 11:41
  • I tried putting a closing parenthesis at the end, but still no luck. Commented Sep 16, 2018 at 10:19
  • @ctrl-alt-delor: I searched for "still no luck" on duckduckgo but got tons of hits which did not seem related to your problem, so I'm not sure how to help you further.
    – Stefan
    Commented Sep 16, 2018 at 21:10
  • Sorry “but still no luck” is an English idiom, meaning “but still it does not work”. Commented Sep 17, 2018 at 12:53
  • @ctrl-alt-delor: but when I ask duckduckgo to search for "but still it does not work" it still doesn't give me any link that seems related. IOW, your description of your problem "still doesn't work" (or more specifically, is still missing): "doesn't work" is not a useful description of your problem, it gives me no more information than saying "I have a problem".
    – Stefan
    Commented Sep 17, 2018 at 13:21

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.