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

From: martin rudalics <[email-masked]>
Date: Mon, 30 Jul 2012 11:13:25 +0200

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

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.

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

Indeed.

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

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

Using `selected-frame' within `after-make-frame-functions' seems awfully
fragile to me.  IMHO this can't ever work reliably.

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

Let's see.

martin