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.