To do its job, this code apparently needs to run once after the first frame has been created. How can I achieve that?
The standard hooks for this are listed under (info "(elisp) Standard Hooks")
:
‘after-make-frame-functions’
‘before-make-frame-hook’
‘server-after-make-frame-hook’
see Creating Frames.
Following the link to (info "(elisp) Creating Frames")
:
-- Variable: before-make-frame-hook
A normal hook run by ‘make-frame’ before it creates the frame.
-- Variable: after-make-frame-functions
An abnormal hook run by ‘make-frame’ after it created the frame.
Each function in ‘after-make-frame-functions’ receives one
argument, the frame just created.
Note that any functions added to these hooks by your initial file are
usually not run for the initial frame, since Emacs reads the initial
file only after creating that frame. However, if the initial frame is
specified to use a separate minibuffer frame (see Minibuffers and
Frames), the functions will be run for both, the minibuffer-less and
the minibuffer frame.
-- User Option: server-after-make-frame-hook
A normal hook run when the Emacs server creates a client frame.
When this hook is called, the created frame is the selected one.
See (emacs)Emacs Server.
(Note that the last server-
hook is new in Emacs 27.)
To ensure a hook function is run only once, after the first non-daemon frame is created, just remove the function from the hook as its last step. For example:
(defun my-configure-font (frame)
"Configure font given initial non-daemon FRAME.
Intended for `after-make-frame-functions'."
;; Do stuff with FRAME...
(remove-hook 'after-make-frame-functions #'my-configure-font))
(add-hook 'after-make-frame-functions #'my-configure-font)
Some things to consider:
- Both
after-make-frame-functions
and server-after-make-frame-hook
are called for non-graphical frames as well, so add appropriate checks for this as needed.
- Neither of these hooks is run in a non-daemon Emacs session. To also support non-daemon sessions, add your function to
window-setup-hook
instead (or as well). To check whether the current session is a daemon or not, there's the predicate daemonp
.
set-frame-font
and similar like having an actual frame to work with, which is why you should set and save the value of thedefault
face usingM-x customize-face
, which will set the appropriate values that will be used by new graphical frames (where do people get theseset-frame-font
invocations from?)