Subject: bug#11939: 24.1; `save-buffers-kill-emacs' loses minibuffer focus when itcalls `list-processes'

From: "Drew Adams" <[email-masked]>
Date: Thu, 19 Jul 2012 10:45:46 -0700

> But choose_minibuf_frame has this
> 
>        /* I don't think that any frames may validly have a 
>           null minibuffer window anymore.  */
>        if (NILP (sf->minibuffer_window))
> 	abort ();

Wow, that comment seems weird.  Unless a frame that has nil as the value of its
`minibuffer' frame parameter is still expected to have a minibuffer _window_.
That's a distinction that is beyond me.  I do not claim to understand things at
the Emacs window level.

But certainly there can be frames that have no minibuffer - their `minibuffer'
frame parameter value is nil.

> and read_minibuf calls choose_minibuf_frame, so if a new frame doesn't
> have a valid minibuffer window, emacs should abort.

What does abort mean here - does it mean that Emacs exits?

> If it does, the latter
>    if (!EQ (mini_frame, selected_frame))
>      Fredirect_frame_focus (selected_frame, mini_frame);
> 
> in read_minibuf should redirect focus but apparently it doesn't.

Again, are you sure it does not?  I've been (stubbornly) guessing that it always
does, but then, in the problematic case we've been looking at, the focus is
grabbed away and given to the new frame that is popped up.

I understand that you don't see it that way, that you instead guess that in this
problematic case there is never any redirection of focus to the minibuffer
frame.  But I haven't yet understood why you think that.  (I do not say you are
wrong.)

>  >>  >> So `1on1-fit-minibuffer-frame' assumes that the selected
>  >>  >> frame is the standalone minibuffer frame and that that
>  >>  >> frame has focus.  Why don't you verify all that in the
>  >>  >> function's body?
>  >>  >
>  >>  > See above - you already asked that.  It _is_ the
>  >>  > minibuffer frame for the call that I expected.  I did not
>  >>  > expect the second call provoked by the frame switch
>  >>  > command (via post-command-hook), with the wrong frame focused.
>  >>
>  >> Can you check somehow that the minibuffer-less frame is focussed?
>  >
>  > Again, I don't know what you mean, or how to do that.
> 
> Probably by checking whether the focus of the minibuffer-less 
> frame A is redirected to the minibuffer-equipped frame B.

I don't know how to do that.

And in `1on1-fit-minibuffer-frame' I do not know how to find out what the
minibuffer-less frame is.  That function is just invoked by `post-command-hook'.

It seems that in the problematic case it is command `handle-switch-frame' that
is the command current when `post-command-hook' does its thing here.  But I
don't know how to determine what frame was switched to.  I can check
`selected-frame', which is what I do, but I'm not sure what you are suggesting I
do.

>  > I was talking only about the minibuffer still being active 
>  > (not exited)
> 
> But what does that mean in practice?  Apart from looping.

In my mind it means only that (active-minibuffer-window) returns non-nil.  But
again, I'm really no expert on this stuff, and I do not pretend to understand
what really happens, especially at the level of Emacs windows.

AFAIK, the only test available to Lisp programmers to tell whether the
minibuffer is active (expecting input), wherever it might be located, is
`active-minibuffer-window'.

>  > It is still my guess that the focus _was_ directed to the 
>  > minibuffer for/by `read-from-minibuffer', but that thereafter
>  > the new frame was popped up and the window mgr gave it the focus
>  > (i.e., took focus away from the minibuffer frame).
> 
> From the window manager's POV the minibuffer-less frame does have
> focus.

OK, but did the minibuffer frame ever receive the focus, after
`read-from-minibuffer' was invoked?  That's the question that I think we are
assuming different answers to.  I'm guessing yes, and I think you are saying no.
I'm guessing yes, but then the window mgr gave the focus instead to the new
frame it created.

> The emacs redirection mechanism works on top of that.
> 
>  > No, I do not have any proof of that, but that's my 
>  > conceptual model so far.
>  >
>  > But you understand this stuff at a better, lower level 
>  > than I: you understand it at the level of windows etc.
> 
> I understand next to nothing about WM windows.

Me too.  I meant Emacs windows.

>  > It is no doubt correct to speak of the minibuffer
>  > window and not (as I did, waving my hands) of the 
>  > "minibuffer" expecting input.
> 
> It makes a difference if you have a minibuffer-less frame that has no
> minibuffer window it can direct input to.

OK.  What's needed I guess is to make sure somehow that every frame redirects
input to the minibuffer frame when the minibuffer becomes active.

Perhaps it would help to imagine the new frame scenario a bit like the
switch-to-*Completions*-frame scenario (dunno).

As I mentioned in my other reply today, you can, when the minibuffer is active,
explicitly switch the focus to the *Completions* frame, to do something there
(e.g. move to some completion candidate).

In Icicles you can do this by hitting `C-insert' from the minibuffer (i.e., in a
minibuffer keymap).  You can then switch back to the minibuffer by hitting
`C-insert' again (this time, that's a key binding in
`completion-list-mode-map').  For example, you can use `C-insert' to move to
*Completions*, then move to a particular completion, then use `C-insert' to move
back to the minibuffer.  The latter `C-insert' brings the candidate back, i.e.,
inserts it into the minibuffer.

Now in the case of the new frame that is popped up while reading from the
minibuffer, the window mgr (I'm supposing) does the equivalent of my `C-insert':
it switches the focus to the new frame, just like `C-insert' switches the focus
to *Completions*.  That's not an intention on the part of the user, but it
happens (due to MS Windows).

So a possible (hack) solution, if we could detect that unprogrammed (in Emacs)
focus switch, might be to automatically switch focus back to the minibuffer
frame (IF the minibuffer is active).

Does this new frame creation necessarily go through Emacs `make-frame'?  Maybe
there is a hook there that could be used for such a hack?  Dunno - just some
rough ideas.