From c873d16af61ae9b956c6dd6d9e50ebad2bb7666e Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Thu, 6 May 2021 10:48:14 +0000 Subject: [PATCH] Fix wrong handling of minibuffers when frames get iconified/made invisible This should fix bug #47766. * lisp/window.el (window-deletable-p): Add a quote where it was missing from minibuffer-follows-selected-frame. * src/frame.c (check_minibuf_window): Delete the function. (delete_frame): In place of calling check_minibuf_window, call move_minibuffers_onto_frame, possibly to move minibuffers onto the new current frame. (Fmake_frame_invisible, Ficonify_frame): Remove calls to check_minibuf_window. * src/minibuf.c (Factive_minibuffer_window): Search the frames for the active minibuffer rather than just assuming minibuf_window has been correctly updated. --- lisp/window.el | 2 +- src/frame.c | 62 ++++---------------------------------------------- src/minibuf.c | 18 ++++++++++++++- 3 files changed, 23 insertions(+), 59 deletions(-) diff --git a/lisp/window.el b/lisp/window.el index cf5752113d5..bba4992ca24 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4117,7 +4117,7 @@ frame can be safely deleted." (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 738bfe9a5c8..cb9d4f52109 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1929,52 +1929,6 @@ other_frames (struct frame *f, bool invisible, bool force) return false; } -/* Make sure that minibuf_window doesn't refer to FRAME's minibuffer - window. Preferably use the selected frame's minibuffer window - instead. If the selected frame doesn't have one, get some other - frame's minibuffer window. SELECT non-zero means select the new - minibuffer window. */ -static void -check_minibuf_window (Lisp_Object frame, int select) -{ - struct frame *f = decode_live_frame (frame); - - XSETFRAME (frame, f); - - if (WINDOWP (minibuf_window) && EQ (f->minibuffer_window, minibuf_window)) - { - Lisp_Object frames, this, window = make_fixnum (0); - - if (!EQ (frame, selected_frame) - && FRAME_HAS_MINIBUF_P (XFRAME (selected_frame))) - window = FRAME_MINIBUF_WINDOW (XFRAME (selected_frame)); - else - FOR_EACH_FRAME (frames, this) - { - if (!EQ (this, frame) && FRAME_HAS_MINIBUF_P (XFRAME (this))) - { - window = FRAME_MINIBUF_WINDOW (XFRAME (this)); - break; - } - } - - /* Don't abort if no window was found (Bug#15247). */ - if (WINDOWP (window)) - { - /* Use set_window_buffer instead of Fset_window_buffer (see - discussion of bug#11984, bug#12025, bug#12026). */ - set_window_buffer (window, XWINDOW (minibuf_window)->contents, 0, 0); - minibuf_window = window; - - /* SELECT non-zero usually means that FRAME's minibuffer - window was selected; select the new one. */ - if (select) - Fselect_window (minibuf_window, Qnil); - } - } -} - - /** * delete_frame: * @@ -1989,7 +1943,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) struct frame *sf; struct kboard *kb; Lisp_Object frames, frame1; - int minibuffer_selected, is_tooltip_frame; + int is_tooltip_frame; bool nochild = !FRAME_PARENT_FRAME (f); Lisp_Object minibuffer_child_frame = Qnil; @@ -2097,7 +2051,6 @@ delete_frame (Lisp_Object frame, Lisp_Object force) /* At this point, we are committed to deleting the frame. There is no more chance for errors to prevent it. */ - minibuffer_selected = EQ (minibuf_window, selected_window); sf = SELECTED_FRAME (); /* Don't let the frame remain selected. */ if (f == sf) @@ -2155,9 +2108,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)) @@ -2788,9 +2742,6 @@ displayed in the terminal. */) 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); @@ -2833,9 +2784,6 @@ for how to proceed. */) } #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 c4482d7f1ee..bc7d4393985 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, -- 2.39.5