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.
This commit is contained in:
Alan Mackenzie 2023-06-21 14:23:14 +00:00
parent a0ccf1859c
commit 4ca371e9cc
6 changed files with 53 additions and 11 deletions

View file

@ -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

View file

@ -11561,7 +11561,7 @@ quit_throw_to_read_char (bool from_signal)
if (FRAMEP (internal_last_event_frame)
&& !EQ (internal_last_event_frame, selected_frame))
do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
0, Qnil);
0, 0, Qnil);
sys_longjmp (getcjmp, 1);
}

View file

@ -4878,7 +4878,7 @@ extern void syms_of_indent (void);
/* Defined in frame.c. */
extern void store_frame_param (struct frame *, Lisp_Object, Lisp_Object);
extern void store_in_alist (Lisp_Object *, Lisp_Object, Lisp_Object);
extern Lisp_Object do_switch_frame (Lisp_Object, int, Lisp_Object);
extern Lisp_Object do_switch_frame (Lisp_Object, int, int, Lisp_Object);
extern Lisp_Object get_frame_param (struct frame *, Lisp_Object);
extern void frames_discard_buffer (Lisp_Object);
extern void init_frame_once (void);

View file

@ -1125,8 +1125,8 @@ read_minibuf_unwind (void)
found:
if (!EQ (exp_MB_frame, saved_selected_frame)
&& !NILP (exp_MB_frame))
do_switch_frame (exp_MB_frame, 0, Qt); /* This also sets
minibuf_window */
do_switch_frame (exp_MB_frame, 0, 0, Qt); /* This also sets
minibuf_window */
/* To keep things predictable, in case it matters, let's be in the
minibuffer when we reset the relevant variables. Don't depend on
@ -1238,7 +1238,7 @@ read_minibuf_unwind (void)
/* Restore the selected frame. */
if (!EQ (exp_MB_frame, saved_selected_frame)
&& !NILP (exp_MB_frame))
do_switch_frame (saved_selected_frame, 0, Qt);
do_switch_frame (saved_selected_frame, 0, 0, Qt);
}
/* Replace the expired minibuffer in frame exp_MB_frame with the next less

View file

@ -7399,7 +7399,7 @@ the return value is nil. Otherwise the value is t. */)
do_switch_frame (NILP (dont_set_frame)
? data->selected_frame
: old_frame
, 0, Qnil);
, 0, 0, Qnil);
}
FRAME_WINDOW_CHANGE (f) = true;

View file

@ -25792,7 +25792,7 @@ x_try_restore_frame (void)
FOR_EACH_FRAME (tail, frame)
{
if (!NILP (do_switch_frame (frame, 1, Qnil)))
if (!NILP (do_switch_frame (frame, 0, 1, Qnil)))
return;
}
}