Subject: bug#51862: after-focus-change-function: hard to understand documentation

From: Stefan Kangas <[email-masked]>
Date: Mon, 15 Nov 2021 03:00:35 -0800

I have the following in my init file:

    (add-hook 'focus-out-hook #'foo-bar)

But `focus-out-hook' is obsolete in 27.1 and replaced with
`after-focus-change-function' (see commit 2f6c682061).  However, I find
it substantially harder to understand how to use the latter.

Please find below some comments based on my reading of the documentation
in (info "(elisp) Input Focus").

> -- Variable: after-focus-change-function This function is an extension
> point that code can use to receive a notification that focus has
> changed.

Why does this use the terminology "extension point"?  We don't use that
anywhere else in the ELisp manual.

Can't it be used for other things than "receiving a notification that
focus has changed"?

>     This function is called with no arguments when Emacs notices that
>     the set of focused frames may have changed.  Code wanting to do
>     something when frame focus changes should use ‘add-function’ to add
>     a function to this one, and in this added function, re-scan the set
>     of focused frames, calling ‘frame-focus-state’ to retrieve the last
>     known focus state of each frame.  Focus events are delivered
>     asynchronously, and frame input focus according to an external
>     system may not correspond to the notion of the Emacs selected
>     frame.  Multiple frames may appear to have input focus
>     simultaneously due to focus event delivery differences, the
>     presence of multiple Emacs terminals, and other factors, and code
>     should be robust in the face of this situation.

This for me comes off as pretty scary.  It sounds to me like I would
need to invest couple of hours at least into understanding all this,
when all I really want to do call a very simple function whenever focus
leaves a frame.

Could we have a simpler interface for this?  If not, could we perhaps
include some examples that would explain in a straightforward way what
one would need to do?

>     Depending on window system, focus events may also be delivered
>     repeatedly and with different focus states before settling to the
>     expected values.  Code relying on focus notifications should
>     “debounce” any user-visible updates arising from focus changes,
>     perhaps by deferring work until redisplay.

How do I "defer work until redisplay"?  Could we have an example?

>     This function may be called in arbitrary contexts, including from
>     inside ‘read-event’, so take the same care as you might when
>     writing a process filter.

Could we have some examples of what care I would need to take, or a
pointer to where that is explained?

Thanks.