Next: Editor-Level Control Flow Modules, Previous: Dispatching Events; The Command Builder, Up: Events and the Event Loop [Contents][Index]
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 select-device
or select-console
.
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
‘*scratch*’.
Whenever a focus-change event is received from the window manager, it
generates a 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
maybe call handle-switch-frame
, or something ...).
In XEmacs, we do change the window-manager frame focus as a
result of 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
implement.
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 redirect-frame-focus
,
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
indicating crockishness.
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
when 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.
Next: Editor-Level Control Flow Modules, Previous: Dispatching Events; The Command Builder, Up: Events and the Event Loop [Contents][Index]