Subject: Re: bug#11566: 24.0.97; `read-from-minibuffer': focus to standalone minibuffer frame?

From: martin rudalics <[email-masked]>
Date: Sun, 27 May 2012 15:22:21 +0200

> On MS Windows at least, when a new frame is created it grabs the input
 > focus.  The problem where the minibuffer frame does not get the focus it
 > needs seems to arise in a situation where a new frame is popped up and
 > then `read-from-minibuffer' is called immediately afterward.  Maybe
 > there is some kind of contention or delay/race problem here (?) - I have
 > no idea.

You should be able to check this by inserting a (sit-for 1) somewhere in
between popping up the frame and calling `read-from-minibuffer'.

 > For example, `dired-mark-read-string' calls `dired-mark-pop-up' to read
 > a string using `read-from-minibuffer' (`r-f-m' is the FUNCTION arg
 > passed to `d-m-p-u' in this case).
 >
 > Inside a `save-window-excursion', `dired-mark-pop-up' then calls
 > `dired-pop-to-buffer', which pops up a new buffer, which (let's say,
 > because of `special-display-regexp' or whatever) is shown in a new
 > frame.  MS Windows gives this frame the input focus.
 >
 > Then, still inside the `save-window-excursion', `dired-mark-pop-up'
 > immediately calls the FUNCTION arg, which in this case is
 > `read-from-minibuffer'.  (It does this using (apply FUNCTION args), but
 > that should not make any difference.)
 >
 > [I don't think it matters for correctness whether the (apply FUNCTION
 > args) is inside the `save-window-excursion'.  I've tried moving it
 > outside, but that did not change anything.  I would think that it should
 > be outside logically (why perform the action from that buffer?), but I'm
 > not knowledgeable about all use cases of `dired-mark-pop-up'.]

IIRC _you_ don't need the `save-window-excursion'.  So replace it with a
`progn' and I'm sure you won't notice any difference.

 > OK, so what happens is this: When `read-from-minibuffer' does its thing,
 > the standalone minibuffer does not receive the user input.  Instead, the
 > input goes to the popped-up frame (which has a list of *Marked Files*).
 >
 > That seems to be an exception to the general rule that
 > `read-from-minibuffer' correctly moves the focus to the minibuffer - and
 > to its frame.

IIUC `read-from-minibuffer' uses `redirect-frame-focus' to send the
keystrokes to the minibuffer window.  If that function works for you in
general, we likely have a race condition in this special case.

 > I don't know why there is a difference in this case, but
 > that seems to be what happens.  The problem is not specific to this
 > example - it can occur at other times.  But I think that this is a good
 > case to follow what's happening.
 >
 > I've tried various workarounds, with more or less success.  But I'm
 > thinking now that the problem is not in any such functions that pop up a
 > frame etc. but rather with `read-from-minibuffer' itself.  Shouldn't it
 > have the responsibility here to give the minibuffer frame the focus?

Yes.  But the window manager must not intercept it.

 > Here is a workaround I've come up with when trying to "fix" `r-f-m'
 > itself:
 >
 > (defadvice read-from-minibuffer (around focus-standalone-minibuf activate)
 >   "..."
 >   (let ((selframe  (selected-frame))
 >         result)
 >     (unwind-protect
 >          (progn (when (and (boundp '1on1-minibuffer-frame)
 >                            (frame-live-p 1on1-minibuffer-frame))
 >                   (select-frame-set-input-focus 1on1-minibuffer-frame))
 >                 (setq result  ad-do-it))
 >       (ignore-errors (select-frame-set-input-focus selframe))
 >       result)))
 >
 > (In my case I know that the standalone minibuffer, if it exists, is the
 > value of `1on1-minibuffer-frame'.  Not sure how the use of a standalone
 > minibuffer would be detected in general - presumably by checking for a
 > frame that has a `minibuffer' parameter with value `only'...)
 >
 > But that defadvice does not always make `r-f-m' DTRT, in any case.  For
 > example, if the originally selected frame is deleted during `ad-do-it',
 > then it punts and leaves the input focus in the minibuffer frame.  What
 > I would probably expect (want) in that case is for the previously
 > selected frame to get the focus.

I'm afraid that in this special case the current code will fail as well.

 > For example, if I tweak `dired-mark-pop-up' so that it deletes the
 > popped up frame at the end, then - since that frame was selected (by the
 > window manager) when `read-from-minibuffer' was called - the minibuffer
 > frame ends up with the focus.
 >
 > (And I do tweak `d-m-p-u' that way, because of another problem with such
 > a popped up frame - see bug #7533.)
 >
 > Any help is appreciated.  Hope I've made the problem clear enough,
 > though you would probably have to be on Windows to see it manifested.
 > I really hope that someone with better understanding than I can help.

Try the sit-for approach.  Try to make a standalone example like

(let ((old-frame ... some existing frame))
   (make-frame)
   (redirect-frame-focus old-frame))

and see whether it fails giving focus to `old-frame'.

martin