Subject: bug#47766: 28.0.50; choose-completion fails

From: Alan Mackenzie <[email-masked]>
Date: Thu, 22 Apr 2021 15:07:47 +0000

Hello, Madhu and Stefan.

On Tue, Apr 20, 2021 at 08:25:13 -0500, Stefan Kangas wrote:
> Gregory Heytings <[email-masked]> writes:

> >> In GNU Emacs 28.0.50 (build 2, x86_64-pc-linux-gnu, Motif Version 2.3.8, cairo
> >> version 1.16.0) of 2021-04-14 built on maher based on master
> >> 844b8949a71f180d395a237c768b22d91cf91ded (with the motif revert reverted)

> >> 1. emacs -Q -eval '(setq pop-up-windows nil pop-up-frames t)'
> >> 2. C-x b TAB

> >> this would pop up a new *Completions* buffer in a new frame with are two
> >> choices *Messages* and *scratch*

> >> 3. choose a completion (click or hit enter on one of the choices)

> >> user-error: Cannot switch buffers in minibuffer window

> > This is because of commit 7c2ebf6e23.

Or, more accurately, because the changes in that commit were incomplete.
In particular, functions iconify-frame and make-frame-invisible were
moving minibuffers in a way no longer consistent with the rest of Emacs.

Madhu, would you please try out the following patch (which gives a couple
of harmless warnings in compilation), and tell us whether it fixes the
problems in your setup, or what is still not working properly.  Thanks!

diff --git a/lisp/window.el b/lisp/window.el
index 071761ea50..faf639cddd 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -4119,7 +4119,7 @@ window-deletable-p
 		  (let ((minibuf (active-minibuffer-window)))
 		    (and minibuf (eq frame (window-frame minibuf))
                          (not (eq (default-toplevel-value
-                                    minibuffer-follows-selected-frame)
+                                    'minibuffer-follows-selected-frame)
                                   t)))))
 	'frame))
      ((window-minibuffer-p window)
diff --git a/src/frame.c b/src/frame.c
index 097cd555c6..a1a6d58cb6 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -2085,9 +2085,10 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
       do_switch_frame (frame1, 0, 1, Qnil);
       sf = SELECTED_FRAME ();
     }
-
-  /* Don't allow minibuf_window to remain on a deleted frame.  */
-  check_minibuf_window (frame, minibuffer_selected);
+  else
+    /* Ensure any minibuffers on FRAME are moved onto the selected
+       frame.  */
+    move_minibuffers_onto_frame (f, true);
 
   /* Don't let echo_area_window to remain on a deleted frame.  */
   if (EQ (f->minibuffer_window, echo_area_window))
@@ -2718,9 +2719,6 @@ DEFUN ("make-frame-invisible", Fmake_frame_invisible, Smake_frame_invisible,
   if (NILP (force) && !other_frames (f, true, false))
     error ("Attempt to make invisible the sole visible or iconified frame");
 
-  /* Don't allow minibuf_window to remain on an invisible frame.  */
-  check_minibuf_window (frame, EQ (minibuf_window, selected_window));
-
   if (FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->frame_visible_invisible_hook)
     FRAME_TERMINAL (f)->frame_visible_invisible_hook (f, false);
 
@@ -2763,9 +2761,6 @@ DEFUN ("iconify-frame", Ficonify_frame, Siconify_frame,
     }
 #endif	/* HAVE_WINDOW_SYSTEM */
 
-  /* Don't allow minibuf_window to remain on an iconified frame.  */
-  check_minibuf_window (frame, EQ (minibuf_window, selected_window));
-
   if (FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->iconify_frame_hook)
     FRAME_TERMINAL (f)->iconify_frame_hook (f);
 
diff --git a/src/minibuf.c b/src/minibuf.c
index c4482d7f1e..bc7d439398 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -212,7 +212,23 @@ DEFUN ("active-minibuffer-window", Factive_minibuffer_window,
        doc: /* Return the currently active minibuffer window, or nil if none.  */)
      (void)
 {
-  return minibuf_level ? minibuf_window : Qnil;
+  Lisp_Object frames, frame;
+  struct frame *f;
+  Lisp_Object innermost_MB;
+
+  if (!minibuf_level)
+    return Qnil;
+
+  innermost_MB = nth_minibuffer (minibuf_level);
+  FOR_EACH_FRAME (frames, frame)
+    {
+      f = XFRAME (frame);
+      if (FRAME_LIVE_P (f)
+	  && WINDOW_LIVE_P (f->minibuffer_window)
+	  && EQ (XWINDOW (f->minibuffer_window)->contents, innermost_MB))
+	return f->minibuffer_window;
+    }
+  return minibuf_window;	/* "Can't happen." */
 }
 
 DEFUN ("set-minibuffer-window", Fset_minibuffer_window,

> Copying in Alan here.

-- 
Alan Mackenzie (Nuremberg, Germany).