On my system, Emacs segfaults if this is run in a daemon before a window is created:
(set-fontset-font (face-attribute 'default :fontset) 'han "Noto Sans Mono CJK JP")
I don't really know how this works, but I just need to prevent it from running during that time. So how do we check if Emacs is running as a daemon but a window hasn't been created?
(I'll go back to calling them “frames” in the rest of this article.)
(terminal-name) is always
"initial_terminal" in a daemon before a frame is created. Like this:
Let's launch a daemon to test with. In one terminal:
emacs -Q --fg-daemon
emacs -Q to not load any extra init files.
Now let's try the obvious. The Emacs manual implies that there will be no existing frame when Emacs is started as a daemon:
If the Emacs process has no existing frame—which can happen if it was started as a daemon (see Emacs Server)—then Emacs opens a frame on the terminal in which you called
emacsclient --eval "(frame-list)"
(#<frame F1 0x5562c8db0ea0>)
emacsclient --eval "(selected-frame)"
#<frame F1 0x5562c8db0ea0>
This frame is even selected.
(frame-live-p) on it returns
t, which means it claims to be displayed on a text based terminal.
Let's try this instead:
emacsclient --eval "(frame-terminal (car (frame-list)))"
#<terminal 0 on initial_terminal>
Now we're getting somewhere. We can use
terminal-name to extract the
initial_terminal name as a string:
emacsclient --eval "(terminal-name (frame-terminal (car (frame-list))))"
And, in fact, because this frame is selected already and
terminal-name automatically uses the selected frame's terminal, we can omit its argument:
emacsclient --eval "(terminal-name)"
In a normal frame, this will return something else:
After finding out the term
initial_terminal it became easier to search for the same answer.
It's a "physically invisible" frame (even though
frame-visible-psays otherwise) associated with initial terminal where the daemon was started. I suspect that a sole reason for its existence is that emacs is not ready to run with no frames at all, and it's hard enough to fix it.
(string-equal (terminal-name (get-device-terminal nil)) "initial_terminal")
to determine the same thing: whether we're in daemon mode and before any frames have been created.
(get-device-terminal nil)returns the display terminal of the selected frame, so
(terminal-name (get-device-terminal nil))is exactly the same as
- This technique is in fact used in Emacs itself, in
debug.el. This was added in Emacs 27, in this commit.
- What is the difference between a terminal and a frame? Terminals are basically output devices. Multiple frames can share the same terminal.
- The “initial terminal” in its current form was added in this commit, released in Emacs 23.