Subject: bug#56305: 29.0.50; 'yes-or-no-p' deselects minibuffer frame

From: martin rudalics <[email-masked]>
Date: Mon, 18 Jul 2022 09:36:28 +0200

> Doesn't terminfo cater for this sort of thing?  Whether it does or not,
 > surely we could set up a set of capability variables, nil/t, a bit like
 > we've got focus-follows-mouse.

The doc-string of 'focus-follows-mouse' says:

   You should set this variable to tell Emacs how your window manager
   handles focus, since there is no way in general for Emacs to find out
   automatically.

So do you mean to add similar options that allows users to tell Emacs
how their window manager is supposed to behave wrt foucs handling, frame
raising and the like?  I suspect most users have no idea how their WM
behaves in these regards.  In either case this would be only tangential
to the current issue.

 > Again, where are our capability variables?

Maybe someone can tell us.

 > C-x o calls next-window and the spec for that, with arguments like
 > ALL-FRAMES and MINIBUF is right on the boundaries of understandability.

'next-window' tries to handle every possible use case instead of DTRT in
the few practical cases.  But that ship sailed a long time ago and now
we can only try to keep the old behavior in place as faithfully as
possible because there are too many callers out there that might depend
on its once established functionality.

 > It strikes me it was really fragile code.  In the middle of the function
 > to switch the current frame there was a difficult to understand ad-hoc
 > section which redirected the focus, sometimes.  Surely that should be
 > done somewhere else (where?) more systematically.

do_switch_frame was Fhandle_switch_frame which was Fselect_frame.  Once
Fselect_frame itself accepted 'switch-frame' events (that's where the
"if (CONSP (frame)" part comes from) and asked for redirecting frame
focus.  Later Fhandle_switch_frame was invented to handle requests
coming from Fselect_frame, Fdelete_frame and switch-frame events.  Then
do_switch_frame was invented and Fhandle_switch_frame became a wrapper
for that.  In 2001 the code for resizing the minibuffer window was added
to do_switch_frame.  In a nutshell, all these additional functions were
provided to better sort out two underlying behaviors:

(1) The WM tells us that it now will direct input to another frame and
     Emacs must select that frame in order to stay in synch with the WM.

(2) Emacs wants to change the selected frame and we have to inform the
     WM about that change so it will direct input to it and call us back
     via (1) that it now will do so.

Be it as it may, the history sketched above should tell C coders to
refrain from calling anything that could end up in any of the functions
mentioned above plus Fselect_window which ends up calling Fselect_frame
when the argument window is on another frame.  These functions may do
lots of things other than resizing minibuffer windows and redirecting
frame focus.  Why on earth should title bar formatting do any of the
following:

- set f->select_mini_window_flag

- mark the window for redisplay or ask to redisplay_other_windows

- call bset_last_selected_window

- call move_minibuffers_onto_frame

- set last_nonminibuf_frame

- set internal_last_event_frame

 > I think we can understand the motivation behind that.  Fselect_window
 > will surely do everything to keep everything consistent and coherent.
 > Just setting the variable is liable to lead to inconsistency and chaos if
 > you're not very careful what you do.  This pattern is not unknown in
 > Emacs, where a high-level function (or command, even) wants to do things
 > which are inconvenient at the nitty-gritty level.

If that were the case, then mode line formatting should have called
Fselect_window long ago.  But Gerd's code from 2001 which "just sets the
variables" is still around and handles that case without larger
complaints ever since.  We fixed the case where a frame's selected
window was not in synch and one where a window got deleted by the mode
line formatting code in between.

 > I don't recall seeing
 > any comments about Fselect_window saying "be careful!".

I'd always try to "be careful" when calling a primitive function from C.

 >> In the sequel, obscure bugs began to pile up, all very difficult to
 >> describe and reproduce (Bug#23124, Bug#24285, Bug#34317) and were fixed
 >> with some trickery.  The origin of all that evil remained in place.
 >
 > What is stopping you fixing it, given that you understand it better than
 > anybody else?

Irony of sorts?  The patch I proposed was categorically refused.

 >> Making the minibuffer follow the selected frame was just the final
 >> stab.
 >
 > That's optional: now, either the MB follows the selected frame or it
 > doesn't.

Setting 'minibuffer-follows-selected-frame' to nil doesn't prevent the
bug from happening here.

 > Commit 6355802033d202....aecceef?  Why not?

Because we had that in Emacs 28.1 and you reverted it for Emacs 28.2.

martin