Subject: Re: bug#44933: 27.1; Ephemeral frame selection shrinks minibuffer

From: Sean Devlin <[email-masked]>
Date: Tue, 1 Dec 2020 15:32:48 -0500

Hi Martin,

> On Dec 1, 2020, at 4:33 AM, martin rudalics <[email-masked]> wrote:
> 
> > I’m not sure I understand. Are you saying a program should not be able
> > to grow the minibuffer window this way? Or just that it will be undone
> > by the next resizing event? (Of course, this is a toy example, so I
> > have no opinion on what the correct behavior should be. I’m just
> > wondering.)
> 
> With 'resize-mini-windows' non-nil, redisplay can resize a normal
> minibuffer window (the one at the bottom of a normal frame) any time
> thus overriding any manual resizing done by the user.  With 'grow-only'
> it cannot auto-shrink it to some value above the minimum one, so if you
> make the window manually very large, redisplay can shrink it only when
> the minibuffer gets empty.  Note that there is no "correct" behavior
> here, everything grew out of fixing inconveniences found in daily use.

I see, so redisplay could happen at any time, and redisplay can resize the minibuffer window (contingent on `resize-mini-windows`). I guess in the extreme case, any code could call the `redisplay` function explicitly.

> 
> > I’ve been playing with this a bit (on a recent Emacs 28.0.50), and I’m not sure I understand the current behavior.
> >
> > For example, I have three frames open and I ran this code in the scratch buffer:
> >
> > (with-current-buffer (window-buffer (minibuffer-window))
> >    (remove-overlays)
> >    (erase-buffer)
> >    (insert "this is some text")
> >    (let ((ov (make-overlay (point) (point) nil t t)))
> >      (overlay-put ov 'after-string "\none\ntwo\nthree")))
> >
> > After moving the point, all I can see is the first line in the minibuffer: “this is some text”. This is true across all three frames.
> >
> > If I select the other frames by clicking on them, the frame that just lost focus will now show all four lines (i.e. including the overlay). The minibuffer windows on the other frames will stay at one line until I select them by clicking and then select some other frame.
> >
> > On the other hand, if I select frames by calling `other-frame` via a key binding, the behavior is slightly different: the minibuffer window on a frame expands to four lines as that frame loses focus, and the minibuffer window on the newly selected frame contracts back down to one line.
> >
> > Are all of these behaviors expected and correct? (Again, I have no opinion; I’m just trying to understand how things are meant to work.)
> 
> Your example is a bit contrived in the sense that just inserting text
> into a minibuffer that is not active is not something redisplay really
> cares about.  Putting that overlay into a prompt and then switching
> frames is more realistic wrt what redisplay really cares about.

Fair point, it’s definitely a contrived example.

> 
> > This function is the process filter for a term process, so it handles
> > new output from the process. After doing so, it iterates over all the
> > windows to see if any contain the process buffer. For any that are, it
> > selects those windows and scrolls those windows appropriately.
> 
> I didn't read the code very attentively but let's make sure one thing:
> The behavior you see happens only when there are at least two frames so
> the
> 
> (setq win (next-window win nil t))
> 
> in 'term-emulate-terminal' and the subsequent
> 
> 		     (select-window win)
> 
> really get executed and the latter selects a _different_ frame thus
> causing the earlier mentioned
> 
>  if (!for_deletion && FRAME_HAS_MINIBUF_P (sf))
>    resize_mini_window (XWINDOW (FRAME_MINIBUF_WINDOW (sf)), 1);
> 
> Maybe you could instrument 'term-emulate-terminal' and 'do_switch_frame'
> (debugging this is probably useless) so that they write something into a
> buffer and we can see the precise interleaving of steps leading to the
> behavior seen.

Yeah, I think it does depend on having multiple frames. In the specific case where I first noticed the strange behavior, my setup was:

Frame X with a window displaying a subprocess running under term
Frame Y with a window displaying some other buffer
Frame Y is selected
Selectrum (https://github.com/raxod502/selectrum) is installed as the completing read implementation

I invoked some command that performed a completing read via selectrum (e.g. `find-file` or similar) with the list of candidates displayed vertically below the prompt. While I was sitting with that prompt, the subprocess sent some output. This induced the temporary selection of frame X via the code in term, which caused the list of completing read candidates to disappear.

Anyway, I’ll perform the instrumentation you suggest, so we can understand specifically what is happening.

> 
> >> With the recently added 'minibuffer-follows-selected-frame' we now have
> >> an additional source of complications to consider.  Maybe you could, as
> >> soon as the implementation of the latter has consolidated, play with the
> >> various values of 'resize-mini-windows' and suggest suitable fixes for
> >> the documentations of 'select-window' and 'select-frame'.
> >
> > Sure, I can do that. Is there a timeline for this or some place I can follow development progress?
> 
> You can try to follow the thread "Stop frames stealing eachothers'
> minibuffers!" on emacs-devel and you will see that we all are quite
> often surprised by how the various versions of Emacs handle switching
> from one minibuffer window to another.

Thanks, I’ll check it out.

> 
> >  From testing the current implementation, it seems selectrum has a
> > similar issue here: when I switch to a new frame, the minibuffer does
> > follow, but the list of candidates is hidden until I enter a new
> > input.
> 
> I suppose "showing the list of candidates" is part of a minibuffer
> interaction and the initial prompt is shown correctly on its frame but
> disappears when moving to another frame via C-x 5 o.  Right?

Yes, exactly. I can try to make a video of this if it would help.

Thanks!

> martin