Subject: bug#24500: 25.1.50; Can't other-window from minibuffer if Ediff control panel frame present

From: Richard Copley <[email-masked]>
Date: Thu, 29 Sep 2016 00:21:11 +0100

On 24 September 2016 at 20:04, martin rudalics <[email-masked]> wrote:
> A simpler scenario with emacs -Q is evaluating
>
> (make-frame '((minibuffer . nil)))
>
> followed by M-x and C-x o in the original frame.
>
>> "C-x o" switches to "some other window in the cyclic ordering of
>> windows".  It does so by calling next-window, which is called in a way
>> that doesn't limit it to return windows only on the current frame.
>
> It this particular case it does so because the minibuffer is (1) active
> and (2) shared by the minibuffer-less frame.
>
>> So what happens here is that next-window returns the window on the
>> Ediff control frame, and Emacs then selects it, and also makes the
>> control frame the selected frame.  But because the original selected
>> frame, when you typed "M-x", was the main frame (and we are still
>> reading from its minibuffer), Emacs switches back to the main frame
>> right away.  And that's what you see: the single window of the Ediff
>> control frame becomes the selected window, but its frame doesn't
>> become the selected frame.
>
> That would be fatal ;-)
>
> At the command prompt the frame of the selected window must be
> invariantly the selected frame.  Try the following snippet:
>
> (defvar frame (make-frame '((minibuffer . nil))))
>
> (define-key ctl-x-map "o" 'my-other-window)
>
> (defun my-other-window ()
>   (interactive)
>   (other-window 1)
>   (with-current-buffer "*scratch*"
>     (goto-char (point-max))
>     (insert
>      (format "sw: %s ... wfsw: %s ... sf: %s ... fff: %s\n"
>              (selected-window)
>              (window-frame (selected-window))
>              (selected-frame)
>              (frame-focus frame)))))
>
> It's easy to see, trying with M-x and C-x o, once from the original and
> once from the minibuffer-less frame, that the difference is with the
> focus of the minibuffer-less frame.  The selected window and the
> selected frame's selected window are always the same.
>
>> Not sure what, if anything, could or should be done about this.
>
> The annoying aspect is that once the minibuffer-less frame is selected,
> another C-x o doesn't get you back to the frame with the minibuffer for
> the simple reason that the minibuffer-less frame has its focus currently
> _not_ redirected.  As a consequence, no combinations of C-g and C-x o
> will get you out of this mess.
>
> I attached two patches that seem to work, but without any warranty (I do
> not fully understand the intentions of frame-focus/focus_frame and
> x_get_focus_frame yet).  The purpose of these patches is to keep the
> ‘next-window’ and ‘other-window’ mechanisms symmetric whenever a frame
> shares its minibuffer with other frames:
>
> (1) The frame.c patch changes the behavior of ‘do_switch_frame’ by
> redirecting focus to another frame that shares this frame's minibuffer
> even when that other frame has no pending minibuffer activity.
>
> (2) The window.c patch simply inhibits ‘next-window’ to select a window
> on a frame that has no pending minibuffer activity.
>
> Please try these patches (only one at a time because the window.c patch
> makes the frame.c patch moot) and tell me whether they have any bad
> effects.
>
> Thanks, martin

Thank you!

With patch (1) the focus can get stuck. Having saved the "my-other-window"
example above as "x.el", from "emacs -Q",

M-x load-file RET x.el RET ;; Creates and selects a minibuffer-less frame.
;; Call the initial frame "frame 1" and the minibuffer-less frame "frame 2".
C-x b window2 RET ;; Select named window in frame 2 for clarity.
C-x 5 o ;; Switch to frame 1
M-x
C-x 5 o ;; Switch to frame 2
C-x o ;; Select window *scratch* in frame 1.
C-x o ;; Select minibuffer.
C-g ;; Quit M-x
;; Selected frame is frame 2 and selected window in frame 2 is "window2",
;; but focus is still redirected to frame 1 (selected window now "*scratch*").
xyzzy ;; Characters are inserted in *scratch*.

No amount of switching between frames 1 and 2 changes the focus
redirection, but clicking inside a window on frame 2 does remove
the redirection and get things back to normal.

I'll try patch (2) later. It sounds logical to me.