Ben’s capsule lecture on focus:
In GNU Emacs
select-frame never changes the window-manager frame
focus. All it does is change the "selected frame". This is similar to
what happens when we call
Whenever an event comes in (including a keyboard event), its frame is
selected; therefore, evaluating
select-frame in ‘*scratch*’
won’t cause any effects because the next received event (in the same
frame) will cause a switch back to the frame displaying
Whenever a focus-change event is received from the window manager, it
switch-frame event, which causes the Lisp function
handle-switch-frame to get run. This basically just runs
select-frame (see below, however).
In GNU Emacs, if you want to have an operation run when a frame is
selected, you supply an event binding for
switch-frame (and then
handle-switch-frame, or something ...).
In XEmacs, we do change the window-manager frame focus as a
select-frame, but not until the next time an event is
received, so that a function that momentarily changes the selected frame
won’t cause WM focus flashing. (#### There’s something not quite right
here; this is causing the wrong-cursor-focus problems that you
occasionally see. But the general idea is correct.) This approach is
winning for people who use the explicit-focus model, but is trickier to
We also don’t make the
switch-frame event visible but instead have
select-frame-hook, which is a better approach.
There is the problem of surrogate minibuffers, where when we enter the minibuffer, you essentially want to temporarily switch the WM focus to the frame with the minibuffer, and switch it back when you exit the minibuffer.
GNU Emacs solves this with the crockish
which says "for keyboard events received from FRAME, act like they’re
coming from FOCUS-FRAME". I think what this means is that, when a
keyboard event comes in and the event manager is about to select the
event’s frame, if that frame has its focus redirected, the redirected-to
frame is selected instead. That way, if you’re in a minibufferless
frame and enter the minibuffer, then all Lisp functions that run see the
selected frame as the minibuffer’s frame rather than the minibufferless
frame you came from, so that (e.g.) your typing actually appears in the
minibuffer’s frame and things behave sanely.
There’s also some weird logic that switches the redirected frame focus
from one frame to another if Lisp code explicitly calls
select-frame (but not if
handle-switch-frame is called),
and saves and restores the frame focus in window configurations,
etc. etc. All of this logic is heavily
#if 0’d, with lots of
comments saying "No, this approach doesn’t seem to work, so I’m trying
this ... is it reasonable? Well, I’m not sure ..." that are a red flag
Because of our way of doing things, we can avoid all this crock.
Keyboard events never cause a select-frame (who cares what frame they’re
associated with? They come from a console, only). We change the actual
WM focus to a surrogate minibuffer frame, so we don’t have to do any
internal redirection. In order to get the focus back, I took the
approach in minibuf.el of just checking to see if the frame we moved to
is still the selected frame, and move back to the old one if so.
Conceivably we might have to do the weird "tracking" that GNU Emacs does
select-frame is called, but I don’t think so. If the
selected frame moved from the minibuffer frame, then we just leave it
there, figuring that someone knows what they’re doing. Because we don’t
have any redirection recorded anywhere, it’s safe to do this, and we
don’t end up with unwanted redirection.