Recently I have come up with a cleaner approach that does not need the 1 second delay before checking available fonts.
In emacs sessions with frames launched via a daemon (emacsclient -c -a''
), the user emacs config is evaluated first and then the frame is created. The font setup is done by emacs only after the frame is created. So the user cannot have any font check code that is evaluated at the same time when the config is evaluated.
BUT.. there is one hook, focus-in-hook
that is bound to be run when GUI emacs (with frame) is run, whether that frame is created by emacs
or emacsclient
.
Below solution is a 3-part solution:
- You need to create a
setup-font-check.el
.
- Add some code to your
init.el
that requires that font check code only when focus-in-hook
is run.
- Use
(with-eval-after-load 'setup-font-check ..)
when you need to do something font specific in your config.
(1) Font check
;; Font Check -- setup-font-check.el
(defvar font-symbola-p nil
"If non-nil, Symbola font is available on the system. This font is required
for emoji and other Unicode 6+ display.")
(when (find-font (font-spec :name "Symbola"))
;; Manually choose a fallback font for Unicode
;; http://endlessparentheses.com/manually-choose-a-fallback-font-for-unicode.html
(set-fontset-font "fontset-default" nil (font-spec :size 20 :name "Symbola"))
(setq font-symbola-p t))
(provide 'setup-font-check)
(2) Requiring setup-font-check
in focus-in-hook
(defun modi/font-check ()
"Do font check, then remove self from `focus-in-hook'; need to run this just once."
(require 'setup-font-check)
(remove-hook 'focus-in-hook #'modi/font-check))
;; For non-daemon, regular emacs launches, the frame/fonts are loaded *before*
;; the emacs config is read. But when emacs is launched as a daemon (using
;; emacsclient, the fonts are not actually loaded until the point when the
;; `after-make-frame-functions' hook is run. But even at that point, the frame
;; is not yet selected (for the daemon case). Without a selected frame, the
;; `find-font' will not work correctly. So we do the font check in
;; `focus-in-hook' instead by which all the below are true:
;; - Fonts are loaded (in both daemon and non-daemon cases).
;; - The frame is selected and so `find-font' calls work correctly.
(add-hook 'focus-in-hook #'modi/font-check)
(3) And here is how you use that setup in your config
;; Example of customizing the new `Info-quoted' face in emacs 25+
(with-eval-after-load 'setup-font-check
(when font-symbola-p
;; Do something that needs the Symbola font
))
PS: You can also use after-make-frame-functions
hook instead of focus-in-hook
. But that hook is run only when you run emacsclient
, not when you run non-daemon emacs
. Also you need to have (select-frame frame)
in the function you add to that hook.