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

From: "Drew Adams" <[email-masked]>
Date: Wed, 18 Jul 2012 20:56:50 -0700

> Can a minibuffer-less frame get the focus?

In what scenario?  I don't know what you are asking.

Of course a minibuffer-less frame can get the focus either programmatically (a
function executing in the minibuffer can select another frame) or through user
interaction (the user can click another frame, etc.).

In my use, the focus can change fairly often, but intentionally (e.g. via a user
initiating some command/key from the minibuffer).

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

I'm pretty sure that I saw earlier (e.g. when I reported the bug) that the new
frame, which was read-only, had the focus.  I could tell via debug messages and
because it raised a buffer-read-only error.

If I remove the test I added that prevents `1on1-fit...' from doing anything if
the minibuffer frame is not selected, I can see that buffer and frame *Process
List* are selected.  And I believe that that is where the typed input goes in
that case.

>  >>  > The minibuffer was still active,
>  >>
>  >> ... you mean `active-minibuffer-window' returned the window of the
>  >> minibuffer-only frame ...
>  >
>  > No, I meant only that the minibuffer was still active: 
>  > accepting typed input.
> 
> When?

Let's not get confused with the language here.  I was not talking about the
minibuffer _frame_ accepting input, i.e., having the focus.  That is of course
the problem.

I was talking only about the minibuffer still being active (not exited) and
`read-from-minibuffer' still expecting input.

>  > My next sentence made it clear that the minibuffer-only 
>  > frame was NOT selected:
>  >
>  >>  > but the selected frame was another one (e.g. *Process List*).
>  >
>  > Now maybe there is no real notion of a minibuffer being 
>  > active, and it is more correct to speak of an minibuffer _window_
>  > being active.
>  >
>  > I was describing things from a (possibly naive) user perspective: a
>  > `read-from-minibuffer' was still in progress; the minibuffer was in
>  > principle available for entering text (but its window was not 
>  > selected).  IOW, if it were selected it would accept input.
> 
> I don't understand: With `minibuffer-auto-raise' nil you can redirect
> focus to a frame A while keeping frame B selected.  Or am I missing
> something?  I'd rather think that a new popped up frame doesn't have
> it's focus redirected yet to the minibuffer frame or something like
> that.

That sounds right to me also.  That is what I wrote (as my "guess") in previous
messages.

>  > Yes. The focus is in the minibuffer frame.  AFAICT, each time
>  > `read-from-minibuffer' is called the focus (correctly) 
>  > moves to that frame.  I have not noticed any case where that did
>  > not happen.  Do you think there are such cases?
> 
> Apparently just the one where a new frame just popped up.

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).
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.  It is no doubt correct to speak of the minibuffer
window and not (as I did, waving my hands) of the "minibuffer" expecting input.

I'm just trying to make sense of this as best I can, without a good
understanding of windows and frames etc.  You need not pay attention to my
interpretations of the behavior.

>  > OK.  I'm not familiar with the code, but it's good to know 
>  > that `h-s-f' (and presumably also `switch-frame') do not affect focus.
> 
> IIUC `handle-switch-frame' has to switch focus only if the frame that
> previosly had focus gets deleted.
> 
>  > I have not noticed that.  In fact, I thought that switching
>  > frames always did seem to change the focus.  But perhaps it is
>  > something else and not just `h-s-f' that actually causes the
>  > focus change (e.g. when you click another frame with
>  > the mouse).  Perhaps it is (always?) the window mgr that 
>  > changes the focus?
> 
> I don't think so since redirecting frame focus and not bringing the
> focussed frame to the foreground works.

I don't see how that contradicts things.  I was not saying that a frame could
not have the focus unless it was in front.

I'm not sure what we're talking about anymore.  What seems to me to be happening
is that the window mgr gives the new frame the focus.  I'm guessing that it does
that after the minibuffer already had the focus (correctly), but I don't know
that for a fact.

But in all other cases (i.e., where there is no such bug), reading from the
minibuffer does move the focus to the minibuffer frame.  To me, the simplest
assumption that fits the observed behavior is that the minibuffer frame did get
the focus for reading input, but then the window mgr popped up the new frame and
gave it the focus.

>  > Yes, but it's still not clear to me just what is going on 
>  > here.  The window mgr changes the focus when it creates the new
>  > frame.  But `1on1-fit-minibuffer-frame' is invoked via 
>  > `post-command-hook', which means that there is a command that
>  > initiates it.  I was thinking that that command must be
>  > `h-s-f', and my testing seemed to confirm that (see fix 
>  > #3, below), but if it is not I would like to know what it really is.
> 
> You can try putting something on `mouse-leave-buffer-hook'.  IIUC
> `handle-switch-frame' calls this even when the mouse is not used.

Did you see the #3 that I referenced?  It seems pretty clear to me that `h-s-f'
is the command whose post-command-hook action invoked
`1on1-fit-minibuffer-frame' the second time.  That was tested vis `this-command'
etc.

>  > If the focus change happens via the window mgr after
>  > `1on1-fit-minibuffer-frame', and if `h-s-f' then provokes 
>  > the second call to `1on1-fit-minibuffer-frame', how can
>  > resetting the focus to the minibuffer frame
>  > before the end of the first `1on1-fit-minibuffer-frame' 
>  > solve the problem?  That resetting would need to take place
>  > after the window mgr changed the focus, no?
> 
> I suppose that Emacs has selected the new frame but not 
> redirected frame focus yet.  Note that each frame (see frame.h)
> has a focus_frame field which, if nil, tells which frame should
> get the input.  If this field is not set and the new frame does
> not have a minibuffer, input gets lost until you manually select
> the minibuffer frame.

Perhaps that is the explanation.  But until I added the test to do nothing if
the minibuffer frame was not selected I had the impression that the *Process
List* buffer had the focus AND received the typed input.

I thought I could tell this from the read-only error.  But I no longer see that
error message now when I take out that test.  I see debug message output saying
that the current buffer and current frame are *Process List*.  But I guess that
is not the same thing as saying that that buffer & frame have the focus for
input.

When this happens, if I click the frame for *Messages* and then type more input,
the debug messages say that the current buffer and frame are *Messages*, but the
typed input is not inserted in *Messages*. 

So maybe you are right that "input gets lost".  It does not appear in any frame,
at least.  Dunno whether the act of adding debug output messages interferes with
what's going on at all.

>  > It seems therefor like the window mgr changes the focus 
>  > _before_ the end of the first `1on1-fit-minibuffer-frame'.
>  > But if I add a `message' call at the end, it shows that the focus
> 
> ... I'm not sure whether "the focus" exists.  Rather, each frame seems
> to either have focus itself or have it redirected elsewhere.  
> But there need not exist one single focus for two different frames.

OK.  I didn't realize that.  So things are more complicated than my simple
conceptual model allows.

>  > is still in the minibuffer frame.  That is what I do not
>  > understand: On the one hand, the focus seems to remain in 
>  > the minibuffer frame throughout the first call to `1-f-m-f'.
>  > On the other hand, explicitly setting the focus to the
>  > minibuffer frame at the end of `1-f-m-f' solves the problem.
>  > Can you explain that?
> 
> Because the focus of the new frame was not yet directed to the
> minibuffer frame, I suppose.

I guess so.

>  > What the function does: fit the minibuffer frame to its 
>  > displayed content.  As I said, the function should be a
>  > no-op if the minibuffer is not active or the
>  > minibuffer frame is not in focus.
> 
> The minibuffer frame can be in focus all the time without 
> ever being selected.
> 
> If you understand it, `one-window-p' is OK.  For me the NOMINI and
> ALL-FRAMES arguments are difficult to understand.
> 
>  >> I think you should make sure two things: (1)
>  >> `1on1-fit-minibuffer-frame' should do something iff the frame in
>  >> question is a minibuffer frame.
>  >
>  > What do you mean by "a minibuffer frame"?  It just has a 
>  > non-nil `minibuffer' parameter?  Or that parameter has a
>  > value of `only'?  Or something else?
> 
> I don't know.  How do usually check whether you are in your 
> minibuffer frame?

I don't usually check.  But if I did I guess I'd do it the way I do in the code
I showed (but which does not seem to work now).  But I'm open to suggestions.

Keep in mind that, apart from this bug, whenever the minibuffer (window) is
active the minibuffer frame is focused (receives the input).

>  > Is the following test not sufficient to ensure that it is 
>  > "a minibuffer frame"?
>  > (eq last-event-frame (window-frame (minibuffer-window)))
> 
> Probably.  I'd have to look how this is assigned.

Thanks for hanging in there.

 - Drew