Subject: Re: bug#71343: 30.0.50; TTY frame doesn't automatically redisplay itself after having closed another frame

From: Eli Zaretskii <[email-masked]>
Date: Sun, 16 Jun 2024 09:33:06 +0300

> From: Daniel Clemente <[email-masked]>
> Date: Sun, 16 Jun 2024 05:40:12 +0000
> Cc: [email-masked], [email-masked]
> 
> I have a new discovery (it's about „initial frame“), you can skip to
> the gdb info below (line 16876).

It's a problematic discovery from where I stand...

> > > Random ideas, without knowing much about terminals.
> > > - Can't an X terminal detect „I've been given X focus“ and pass this
> > > signal to the program running inside it?
> >
> > You assume that it will be a terminal belonging to Emacs that will get
> > focus?  That is not given.
> 
> I was thinking that maybe X always does this (X notifies the terminal
> emulator, which notifies the program running inside it, whatever
> program it is).

Emacs doesn't really talk to the terminal emulator, unless the
emulator supports known protocols of doing so.  You will see in
lisp/term/xterm.el that Emacs supports that for xterm that is new
enough.  Don't know what happens with urxvt, but did you try using
xterm and saw the same problems?

> > > - What if, when resizing the frame (something which Emacs detects),
> > > Emacs knows/detects that a frame was closed, and decides not to delay
> > > the redisplay?
> >
> > Redisplay of which frame?  Emacs only redisplays a frame if some
> > change in buffer text justifies that.
> 
> I propose it should repaint/redisplay the frame whose size changed.

When a frame is resized, it is redisplayed, yes.  But that requires
Emacs to know that it is resized.

> Don't we know which frame is the one being resized? It should be f in
> adjust_frame_size. It realizes that e.g. it's being resized from 72 to
> 61 columns.

I need a backtrace showing the call to adjust_frame_size, of a frame
that is not redrawn.  I don't think I saw such a backtrace.

> In normal conditions, resizing a frame calls: adjust_frame size, then
> redisplay_internal, then clear_garbaged_frames, then redraw_frame
> 
> But when I reproduce this bug (i.e. just after closing a frame),
> resizing a frame calls: adjust_frame_size, then redisplay_internal. It
> doesn't call the other two.
> (Only later when I press a key, it calls redisplay_internal, then
> clear_garbaged_frames, then redraw_frame)
> In this scenario, why doesn't redisplay_internal reach the point where
> it calls clear_garbaged_frames?
> Because this happens:
> Breakpoint 5, redisplay_internal () at xdisp.c:16831
> 16831      struct window *w = XWINDOW (selected_window);
> (gdb) n
> 16835      bool must_finish = false, match_p;
> (gdb)
> 16839      bool polling_stopped_here = false;
> (gdb)
> 16846      int hscroll_retries = 0;
> (gdb)
> 16854      int garbaged_frame_retries = 0;
> (gdb)
> 16862      bool update_miniwindow_p = false;
> (gdb)
> 16864      redisplay_trace ("redisplay_internal %d\n", redisplaying_p);
> (gdb)
> 16870      if (redisplaying_p)
> (gdb)
> 16876      if ((FRAME_INITIAL_P (SELECTED_FRAME ())
> (gdb)
> 16877           && redisplay_skip_initial_frame)
> (gdb)
> 16879        return;
> (gdb)
> 
> 
> So, apparently it thinks that my frame is initial.

And for a good reason:

> Some more data about the looks-initial frame:
> 
> (gdb) p *SELECTED_FRAME()
> $102 = {
>   header = {
>     size = 4611686018595348501
>   },
[...]
>   output_data = {
>     tty = 0x0,
>     x = 0x0,
>     w32 = 0x0,
>     ns = 0x0,
>     pgtk = 0x0,
>     haiku = 0x0,
>     android = 0x0
>   },

This zero value exactly means this frame is "initial" it has not yet
been set up as a terminal frame.  That setup happens inside
make-terminal-frame, here:

  f = make_terminal_frame (t);

and make_terminal_frame does

  f->output_method = output_termcap;

Somehow this frame escaped this code, so all kinds of weird things can
happen with it.

> By the way, C-x # isn't enough to close any Emacs frame. If I have
> opened it by running   urxvtcd -e 'emacsclient' '-nw', then later C-x
> # doesn't close it, it just says „No server buffers remain to edit“.
> But C-x C-c does close it.

Use "C-x 5 0" to delete the current frame.