From 4ca371e9cc7178572cc25cbe47371c0075405ff7 Mon Sep 17 00:00:00 2001 From: Alan Mackenzie Date: Wed, 21 Jun 2023 14:23:14 +0000 Subject: Fix bug#64152 (Minibuffer sometimes goes "modal") In particular, when a frame has no minibuffer and is using that of a different "normal" frame, C-x 5 o, etc., and GUI operations fail. Fix by partially reverting the commit from 2022-07-07 15:38:09 +0000 "Remove obscure, obsolete code from do_switch_frame". As a consequent change, also revert the commit from 2022-07-08 20:19:03 +0000 "Remove now unused parameter TRACK from do_switch_frame". * src/frame.c (do_switch_frame): Restore the TRACK parameter. Restore the code which redirects the frame focus when a new frame gets selected. * src/frame.c (Fselect_frame, Fhandle_switch_frame) (delete_frame) * src/keyboard.c (quit_throw_to_read_char) * src/lisp.h (do_switch_frame prototype) * src/minibuf.c (read_minibuf_unwind) * src/window.c (Fset_window_configuration): Restore the TRACK argument to do_switch_frame. * src/xterm.c (x_try_restore_frame): Add a zero TRACK argument to do_switch_frame. --- src/frame.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'src/frame.c') diff --git a/src/frame.c b/src/frame.c index 38a6583605c..fc6a3459482 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1444,6 +1444,10 @@ affects all frames on the same terminal device. */) If FRAME is a switch-frame event `(switch-frame FRAME1)', use FRAME1 as frame. + If TRACK is non-zero and the frame that currently has the focus + redirects its focus to the selected frame, redirect that focused + frame's focus to FRAME instead. + FOR_DELETION non-zero means that the selected frame is being deleted, which includes the possibility that the frame's terminal is dead. @@ -1451,7 +1455,7 @@ affects all frames on the same terminal device. */) The value of NORECORD is passed as argument to Fselect_window. */ Lisp_Object -do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord) +do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object norecord) { struct frame *sf = SELECTED_FRAME (), *f; @@ -1473,6 +1477,44 @@ do_switch_frame (Lisp_Object frame, int for_deletion, Lisp_Object norecord) else if (f == sf) return frame; + /* If the frame with GUI focus has had it's Emacs focus redirected + toward the currently selected frame, we should change the + redirection to point to the newly selected frame. This means + that if the focus is redirected from a minibufferless frame to a + surrogate minibuffer frame, we can use `other-window' to switch + between all the frames using that minibuffer frame, and the focus + redirection will follow us around. This code is necessary when + we have a minibufferless frame using the MB in another (normal) + frame (bug#64152) (ACM, 2023-06-20). */ +#ifdef HAVE_WINDOW_SYSTEM + if (track && FRAME_WINDOW_P (f) && FRAME_TERMINAL (f)->get_focus_frame) + { + Lisp_Object gfocus; /* The frame which still has focus on the + current terminal, according to the GUI + system. */ + Lisp_Object focus; /* The frame to which Emacs has redirected + the focus from `gfocus'. This might be a + frame with a minibuffer when `gfocus' + doesn't have a MB. */ + + gfocus = FRAME_TERMINAL (f)->get_focus_frame (f); + if (FRAMEP (gfocus)) + { + focus = FRAME_FOCUS_FRAME (XFRAME (gfocus)); + if (FRAMEP (focus) && XFRAME (focus) == SELECTED_FRAME ()) + /* Redirect frame focus also when FRAME has its minibuffer + window on the selected frame (see Bug#24500). + + Don't do that: It causes redirection problem with a + separate minibuffer frame (Bug#24803) and problems + when updating the cursor on such frames. + || (NILP (focus) + && EQ (FRAME_MINIBUF_WINDOW (f), sf->selected_window))) */ + Fredirect_frame_focus (gfocus, frame); + } + } +#endif /* HAVE_X_WINDOWS */ + if (!for_deletion && FRAME_HAS_MINIBUF_P (sf)) resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1); @@ -1574,7 +1616,7 @@ This function returns FRAME, or nil if FRAME has been deleted. */) /* Do not select a tooltip frame (Bug#47207). */ error ("Cannot select a tooltip frame"); else - return do_switch_frame (frame, 0, norecord); + return do_switch_frame (frame, 1, 0, norecord); } DEFUN ("handle-switch-frame", Fhandle_switch_frame, @@ -1590,7 +1632,7 @@ necessarily represent user-visible input focus. */) kset_prefix_arg (current_kboard, Vcurrent_prefix_arg); run_hook (Qmouse_leave_buffer_hook); - return do_switch_frame (event, 0, Qnil); + return do_switch_frame (event, 0, 0, Qnil); } DEFUN ("selected-frame", Fselected_frame, Sselected_frame, 0, 0, 0, @@ -2108,7 +2150,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) Fraise_frame (frame1); #endif - do_switch_frame (frame1, 1, Qnil); + do_switch_frame (frame1, 0, 1, Qnil); sf = SELECTED_FRAME (); } else -- cgit v1.2.3-70-g09d2