Subject: RE: bug#11939: 24.1; `save-buffers-kill-emacs' loses minibuffer focuswhenit calls `list-processes'

From: "Drew Adams" <[email-masked]>
Date: Wed, 1 Aug 2012 09:34:47 -0700

>  > I think this all goes back to the problem of 
>  > distinguishing a frame that is popped up only for
>  > informational purposes, _during a user interaction/dialog_,
>  > from a frame that is popped up with the intention of using 
>  > its buffer (as the `current-buffer').
> 
> Yes.
> 
>  > IOW, the case that we were trying to solve, whether for 
>  > the popup showing active processes or the popup showing
>  > marked files in Dired, is a case where the frame
>  > is popped up only to ask a question in the minibuffer.  It 
>  > is only in that case that the input focus should be
>  > directed to the minibuffer.
>  >
>  > How to distinguish that case, I don't know.  But it seems 
>  > like the invariant should be that whenever the minibuffer
>  > is being used for input its frame should have the focus.
> 
> I don't believe the underlying mechanism for popping up 
> frames ever will have the necessary knowledge to decide.

Agreed.  (I almost want to say "Of course", but I did pose the question.)

My contention from the beginning (i.e., before this thread, in other
discussions) is that we need an explicit notion of a minibuffer dialog that
should keep the focus in the minibuffer, so that code can ensure that popped up
frames do not grab the focus away from the minibuffer during the dialog.  Or if
they do, other than via Emacs code or a user action - e.g. via MS Windows, then
they are properly redirected back.

In terms of implementation it could perhaps be a `with-*<something>'
encapsulation.  A given code context DOES know when it is using a popup window
(which could thus be a popup frame) only to provide information while asking a
minibuffer question, and it can wrap the minibuffer interaction and frame
creation in such an encapsulation.

The encapsulation would redirect any new frames created to the minibuffer for
the duration.  But it would need to allow Emacs code within it the possibility
of redirecting the focus (even using a recursive minibuffer invocation that is,
itself, not so encapsulated?).  And it would of course need to allow the user to
explicitly change the focus.

IOW, it would handle new informational frames the way a standalong *Completions*
frame is handled: when it is displayed its focus is redirected to the minibuffer
frame, but that does not prevent Emacs code or the user from switching the focus
to it during minibuffer activity.  

See the code I sent for my *Completions* frame for an example.  It does this
when it displays *Completions* (the selected-frame):
(redirect-frame-focus (selected-frame) 1on1-minibuffer-frame)

>  > That is the problem that needs solving, I think: how to 
>  > ensure that all minibuffer interaction takes place (always)
>  > with the minibuffer frame having the
>  > input focus.

No, I was wrong about that "(always)" - see below.

>  > I also tried this:
>  >
>  > (add-hook 'minibuffer-setup-hook
>  >           (lambda ()
>  >             (unless (eq (selected-frame)
>  >                         (window-frame (minibuffer-window)))
>  >               (redirect-frame-focus (selected-frame)
>  >                 (window-frame (minibuffer-window))))))
>  >
>  > But that had the same effect: the `n' of "no" went to the 
>  > *Process List* frame.  And I added a call to `message'
>  > before the `unless', to see what (selected-frame) was.
>  > And I was surprised to see that it was in fact the
>  > minibuffer frame (so the `unless' became a no-op)  So it 
>  > seems that the minibuffer frame was selected, but did not
>  > receive input (did not have the focus).
> 
> Yes.  In read_minibuf the
>
>    Fset_window_buffer (minibuf_window, Fcurrent_buffer (), Qnil);
>    Fselect_window (minibuf_window, Qnil);
>
> comes before
>
>    Frun_hooks (1, &Qminibuffer_setup_hook);
> 
>  > Finally, knowing that the selected frame is the minibuffer 
>  > frame, but it does not have the focus, I tried this:
>  >
>  > (add-hook 'after-make-frame-functions
>  >           (lambda (frame)
>  >             (when (eq (selected-frame)
>  >                       (window-frame (minibuffer-window)))
>  >               (redirect-frame-focus frame
>  >                 (window-frame (minibuffer-window))))))
>  >
>  > And that solves the problem.  IOW, that does just as much 
>  > good as the systematic redirection (i.e., without the
>  > `when') did, but it does not have the drawback
>  > that each time a frame is popped up it loses the focus to 
>  > the minibuffer frame.
> 
> Using `selected-frame' within `after-make-frame-functions' 
> seems awfully fragile to me.  IMHO this can't ever work reliably.

I cannot speak to that; you're the expert here.  But do you have a
counter-example, just for the sake of concreteness?  (Not important, just
wondering.)

>  > (The only remaining problem is the other one we discussed, 
>  > regarding the value of (current-buffer) after the
>  > minibuffer is exited, so that a subsequent `C-x k'
>  > has " *Minibuf-0*" as the default buffer name.)
>  >
>  > That's the best thing I've come up with, but perhaps you 
>  > have a suggestion.  `after-make-frame-functions' seems
>  > like the right place to do the deed, because it knows
>  > about the new frame, which is the one whose focus needs
>  > to be redirected.

I want to say "ONLY IT knows..." (among existing hooks), but I am not sure of
that.  IOW, of the hooks I am aware of, this one seems the most pertinent here.

>  > Again, this all seems to underline the need for a 
>  > notion/mechanism of defining or detecting a user dialog

I think you are probably right that "detecting" might be a pipe dream.  What I
really have had in mind is mentioned above: the code would encapsulate a
minibuffer reading that might pop up an informational window, redirecting focus
for any new frames to the minibuffer.

>  > that uses the minibuffer while popping up an informational
>  > frame only for the duration of the minibuffer interaction
>  > (input).

The important point here is "informational...only".

And this is where I need to mention an example of why it is not a solution to do
this redirection systematically, testing only
(when (eq (selected-frame) (window-frame (minibuffer-window))).

A case in point is the debugger.  In my setup *Backtrace* pops up in a
special-display frame.  It is not the case that this buffer is for information
only.  It is truly necessary that *Backtrace* receive the focus.  So this is a
good case where my redirection "fix" does not do the right thing.

>  > Anyway, I will use that code (the last above) for a while, 
>  > to see how it goes.

See previous.  I was mistaken in supposing that doing this systematically would
DTRT.  There are clearly some cases where a frame is popped up during minibuffer
input, and that frame is NOT only for informational purposes but should in fact
receive the input focus.

It is only the code that invokes reading from the minibuffer and pops up the
other window/frame that can know whether the focus should be in that
window/frame or in the minibuffer.

But here's the thing: in the case of windows instead of frames, Emacs DTRT, no?
Emacs distinguishes the case of window *Process List* from window *Backtrace*,
giving the focus to the latter and not to the former.  Why can't we make Emacs
DTRT for frames, just as it does for windows?

I know that MS Windows altering the focus throws a monkey wrench into the mix,
but surely we can find some way to KEEP the focus (i.e. re-focus if necessary)
where Emacs put it (correctly).