Subject: Re: bug#23689: Daemon-mode on Windows - "w32-initialized" is set too early

From: Eli Zaretskii <[email-masked]>
Date: Sat, 04 Jun 2016 18:01:15 +0300

> From: Paul Moore <[email-masked]>
> Date: Sat, 4 Jun 2016 13:54:59 +0100
> Cc: [email-masked]
> 
> When spacemacs starts up, it wants to set the fonts as configured by
> the user. To do so, it checks that the user-selected font exists using
> find-font (there's new code in the develop branch that allows the user
> to set a list of fonts, and picks the first on the list that actually
> exists on the system). But in daemon mode, find-font doesn't return a
> useful value until the display system is initialised, so there's a
> macro:
> 
> (defmacro spacemacs|do-after-display-system-init (&rest body)
>   "If the display-system is initialized, run `BODY', otherwise,
> add it to a queue of actions to perform after the first graphical frame is
> created."
>   `(let ((init (cond ((boundp 'ns-initialized) 'ns-initialized)
>                      ((boundp 'w32-initialized) 'w32-initialized)
>                      ((boundp 'x-initialized) 'x-initialized)
>                      (t 't))))           ; fallback to normal loading behavior
>      (if (symbol-value init)
>          (progn
>            ,@body)
>        (push (lambda () ,@body) spacemacs--after-display-system-init-list))))
> 
> The actions on spacemacs--after-display-system-init-list are executed
> when the first GUI frame is displayed, via advice on
> server-create-window-system-frame.

If spacemacs has a way to run code when the first GUI frame is
created, why cannot it do everything at that time?  Why does it have
to test the above conditions on top of that?

> This process works fine on non-Windows systems, I guess because
> ns-initialized and x-initialized are false during daemon startup. But
> on Windows it fails and from my testing this appears to be because
> w32-initialized is true at this point (unlike the other two). As a
> result, the font selection code gets run immediately - specifically
> *before* the point when find-font will give a correct answer.

I think spacemacs should not rely on the other FOO-initialized
variables, either, even if they appear to work for now.  They are not
intended to serve as evidence or trigger for any application-level
logic.  Instead, it should do this in a hook function (make-frame
provides at least 2).

> To demonstrate, create a .emacs.d/init.el containing
> 
> (progn
>     (message "%S" w32-initialized)
>     (message "%S" (find-font (font-spec :name "Courier New")))
>     (message "%S" w32-initialized))
> 
> Set HOME to the directory containing .emacs.d and run emacs --daemon.
> The result is
> 
> t
> nil
> t
> 
> Do the same on Unix (I used Ubuntu) using x-initialized (and a font
> that exists on the Unix system in place of Courier New) and you get
> 
> nil
> nil
> nil
> 
> Do the same using emacs (no --daemon) and look in the *Messages*
> buffer, and you see
> 
> t
> <a font object>
> t
> 
> in both cases.

That "window-system initialized" automatically implies that find-font
will work is IMO an invalid assumption.  Exactly what parts of the
initialization are run in FOO-initialize functions is implementation
detail.  I recommend to stay away of such assumption and instead use
the hooks we provide during startup.  Even if you come to the
conclusion that no existing hook serves spacemacs well enough, and we
then (say) add yet another hook, the result will be cleaner than
relying on semi-documented variables and undocumented assumptions.