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:
parent
a0ccf1859c
commit
4ca371e9cc
6 changed files with 53 additions and 11 deletions
50
src/frame.c
50
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue