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

From: martin rudalics <[email-masked]>
Date: Wed, 18 Jul 2012 18:16:17 +0200

> It does now.  I did not realize that creation of a new frame by MS Windows with
 > the minibuffer frame selected (& having the focus) would change the focus.  And
 > I did not realize that such a change in focus would provoke another invocation
 > of that function (via command `handle-switch-frame', apparently), with the
 > minibuffer frame unfocused.

Can a minibuffer-less frame get the focus?

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

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

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

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

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

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

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

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

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

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

 > FYI, this is the full condition under which it will not be a no-op:
 >
 > ;; We could assume the minibuffer frame is `1on1-minibuffer-frame', but we do
 > not.
 > (and 1on1-fit-minibuffer-frame-flag
 >      (active-minibuffer-window)
 >      ;; Do this because this command is on `post-command-hook',
 >      ;; and an event such as `handle-switch-frame' might have
 >      ;; changed the selected frame.
 >      (eq last-event-frame (window-frame (minibuffer-window)))
 >      (save-selected-window
 >        (select-window (minibuffer-window))
 >        ;; We should be able to use just (one-window-p),
 >        ;; but an Emacs bug means we need this:
 >        (one-window-p nil 'selected-frame)))
 >
 > Perhaps you see some improvement/simplification possible there.  (I don't recall
 > what Emacs bug was involved wrt the last clause or what release that bug is in,
 > FWIW.)
 >
 > And yes, I know that you feel that `one-window-p' is not the right way to check
 > for one-windowness.  But I need this to work for multiple Emacs versions, and so
 > far I've found that `one-window-p' DTRT.  Still, I'm open to suggestions if you
 > see an improvement here.

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?

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

 > Let me know if you think I should add an additional test or replace that test
 > with another.
 >
 >> (2) `1on1-fit-minibuffer-frame' should avoid having any
 >> side-effects wrt window selection or focus unless you explictly want that.
 >
 > That is the case - it has no side effects wrt window selection or focus.  The
 > selection window and the focus are at the end what they were at the beginning.
 >
 > All it does, when it is not a no-op, is (maybe) resize and reposition the
 > minibuffer frame.

OK.

martin