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

From: "Drew Adams" <[email-masked]>
Date: Sun, 29 Jul 2012 12:26:07 -0700

[off-list]:
> I have not been using that `add-hook' in my normal use of 
> Emacs, but I am going to start doing so now, to see if it has 
> any negative effects.  I'll keep you posted if I find any.

No sooner did I try than I ran into problems.

Just `C-x 4 f some-file' is enough to see that this (the `add-hook' to redirect
focus) is not a fix.  After `C-x 4 f some-file', the new frame does not have the
input focus - the minibuffer frame has it (so `C-f' etc. do the wrong thing).

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').

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.

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.

I then tried this, instead:

(add-hook 'after-make-frame-functions
          (lambda (frame)
            (when (active-minibuffer-window)
              (redirect-frame-focus frame
                (window-frame (minibuffer-window))))))

But that is no good because the minibuffer is not active quite yet, at the
moment the hook takes effect.  It is apparently the case that FIRST the new
frame is created and THEN the minibuffer is used/activated.

In the *shell* scenario, when I hit `C-x C-c' and try to type "no", the `n'
invokes `View-search-last-regexp-forward' - I get this:

Signaling: (error "No previous View-mode search")
  signal(error ("No previous View-mode search"))
  error("No previous View-mode search")
  view-search(1 nil)
  View-search-last-regexp-forward(1)
  call-interactively(View-search-last-regexp-forward)
  yes-or-no-p("Active processes exist; kill them and exit anyway? ")
  save-buffers-kill-emacs(nil)
  call-interactively(save-buffers-kill-emacs)

That is with Emacs 20, where buffer *Process List* is in View mode, where `n' is
bound to `View-search-last-regexp-forward'.  In Emacs 24.1, I don't get the
error, but the behavior is similar (the `n' is typed into frame *Process List*,
not into the minibuffer frame).

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).

I then got rid of the `unless' guard, and just redirected systematically, in
`minibuffer-setup-hook', and I still got the same behavior (the typed `n' went
to the *Process List* frame).  Clearly, that just redirected the minibuffer
frame (the selected frame) to itself, whereas what is needed is to redirect the
newly created *Process List* frame's focus to the minibuffer frame.

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 focust to the minibuffer frame.

(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.

Again, this all seems to underline the need for a notion/mechanism of defining
or detecting a user dialog that uses the minibuffer while popping up an
informational frame only for the duration of the minibuffer interaction (input).

Anyway, I will use that code (the last above) for a while, to see how it goes.
Hope this info helps a bit.