GNU bug report logs - #71343
30.0.50; TTY frame doesn't automatically redisplay itself after having closed another frame

Previous Next

Package: emacs;

Reported by: Daniel Clemente <n142857 <at> gmail.com>

Date: Mon, 3 Jun 2024 15:56:01 UTC

Severity: normal

Found in version 30.0.50

Full log


Message #23 received at 71343 <at> debbugs.gnu.org (full text, mbox):

From: Daniel Clemente <n142857 <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: eggert <at> cs.ucla.edu, 71343 <at> debbugs.gnu.org
Subject: Re: bug#71343: 30.0.50; TTY frame doesn't automatically redisplay
 itself after having closed another frame
Date: Sun, 16 Jun 2024 05:40:12 +0000
I have a new discovery (it's about „initial frame“), you can skip to
the gdb info below (line 16876).


> > 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).
I brainstorm ideas without X knowledge; please ignore the bad ones.
But I think „window focus“ isn't the main issue here; more on this below.

> > - What if, when closing a TTY frame in emacsclient, all other frames
> > are redisplayed
>
> Why?

This one is a bad idea, or a last resort solution, in case there's no
other way to detect that some frames (or which ones) may need to be
refreshed.

>
> > - 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.
Maybe I'm not using the right word, „redisplay“. What I mean is that
it should refresh its contents („frame redraw“ I think it's called) to
use the new size. For instance if I make the frame wider, now there's
more space, more words fit in each line, the minibuffer needs to be
extended to the right. Even if the buffer text didn't change.
I have 2 frames, kill the 2nd one, and resize the 1st one. Right now,
Emacs is indeed running adjust_frame_size, and it decides not to
repaint the contents; instead it leaves black areas. (Just in this
case after having closed a frame). This does seem like a bug, because
any type of frame size change should trigger a refresh to use the new
size.

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.

(gdb) info locals
w = 0x7fffffffc000
text_area_y = -16112
text_area_x = -16288
text_area_width = -16128
text_area_height = 1102416563
unit_width = 1
unit_height = 1
old_native_width = 72
old_native_height = 50
new_native_width = 61
new_native_height = 50
min_inner_width = 2
min_inner_height = 4
r = 0x62100022d130
old_inner_width = 72
old_inner_height = 49
new_inner_width = 61
new_inner_height = 49
old_text_cols = 72
old_text_lines = 49
new_text_cols = 61
new_text_lines = 49
old_text_width = 72
old_text_height = 49
inhibit_horizontal = true
inhibit_vertical = true
frame = XIL(0x621000181105)

And yet it doesn't redraw.
I'm still learning the internals to be able to understand what
happens. resize_frame_windows does its job. pool_changed_p (in
adjust_frame_glyphs_for_frame_redisplay) is true. display_completed is
true. FRAME_GARBAGED_P (f) is true. Later in do_pending_window_change
delayed_size_change is false. When later I press a key,
clear_garbaged_frames is run (invoked by redisplay_internal)

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.

But from a first view, that doesn't look right. The frame I'm resizing
isn't initial.
It even has a glyph matrix, 2 windows, …
If I open 4 frames, close the 4th one and resize the 3rd one, it sees
it as initial.

This part of the code is new to me. I'll research it more but I wanted
to send this information now.

I have also seen that some of my frames have f->terminal->name =
"initial_terminal", I don't know if that's related or bad.

Some more data about the looks-initial frame:

(gdb) p *SELECTED_FRAME()
$102 = {
  header = {
    size = 4611686018595348501
  },
  name = XIL(0x555557e78944),
  icon_name = XIL(0),
  title = XIL(0),
  last_mouse_device = XIL(0),
  focus_frame = XIL(0),
  root_window = XIL(0x621000004125),
  selected_window = XIL(0x621000004125),
  old_selected_window = XIL(0x621000004125),
  minibuffer_window = XIL(0x6210000043bd),
  param_alist = XIL(0x7ffff18bc633),
  scroll_bars = XIL(0),
  condemned_scroll_bars = XIL(0),
  menu_bar_items = XIL(0x6210000ca905),
  face_hash_table = XIL(0x621000004655),
  menu_bar_vector = XIL(0),
  buffer_predicate = XIL(0),
  buffer_list = XIL(0x7ffff00cbe23),
  buried_buffer_list = XIL(0),
  tool_bar_position = XIL(0xfab0),
  tab_bar_items = XIL(0),
  tool_bar_items = XIL(0),
  face_cache = 0x604000000ad0,
  last_tab_bar_item = 0,
  menu_bar_items_used = 0,
  current_pool = 0x603000002fe0,
  desired_pool = 0x603000002fb0,
  desired_matrix = 0x616000001280,
  current_matrix = 0x616000001580,
  glyphs_initialized_p = true,
  resized_p = false,
  default_face_done_p = false,
  already_hscrolled_p = false,
  updated_p = false,
  fonts_changed = false,
  cursor_type_changed = false,
  redisplay = true,
  visible = 1,
  iconified = false,
  garbaged = false,
  wants_modeline = true,
  auto_raise = false,
  auto_lower = false,
  no_split = false,
  explicit_name = false,
  window_change = false,
  window_state_change = false,
  mouse_moved = false,
  pointer_invisible = false,
  frozen_window_starts = false,
  output_method = output_initial,
  can_set_window_size = true,
  after_make_frame = true,
  tab_bar_redisplayed = false,
  tab_bar_resized = false,
--Type <RET> for more, q to quit, c to continue without paging--
  tool_bar_redisplayed = false,
  tool_bar_resized = false,
  inhibit_horizontal_resize = false,
  inhibit_vertical_resize = false,
  face_change = true,
  inhibit_clear_image_cache = false,
  new_size_p = false,
  was_invisible = false,
  select_mini_window_flag = false,
  change_stamp = 14,
  number_of_windows = 2,
  tab_bar_lines = 0,
  tab_bar_height = 0,
  n_tab_bar_rows = 0,
  n_tab_bar_items = 0,
  tool_bar_lines = 0,
  tool_bar_height = 0,
  n_tool_bar_rows = 0,
  n_tool_bar_items = 0,
  decode_mode_spec_buffer = 0x613000002f80 '\276' <repeats 200 times>...,
  insert_line_cost = 0x0,
  delete_line_cost = 0x0,
  insert_n_lines_cost = 0x0,
  delete_n_lines_cost = 0x0,
  text_cols = 80,
  text_lines = 24,
  text_width = 80,
  text_height = 24,
  total_cols = 80,
  total_lines = 25,
  pixel_width = 80,
  pixel_height = 25,
  new_width = -1,
  new_height = -1,
  left_pos = 0,
  top_pos = 0,
  win_gravity = 0,
  size_hint_flags = 0,
  border_width = 0,
  child_frame_border_width = 0,
  internal_border_width = 0,
  right_divider_width = 0,
  bottom_divider_width = 0,
  left_fringe_width = 0,
  right_fringe_width = 0,
  fringe_cols = 0,
  menu_bar_lines = 1,
  menu_bar_height = 1,
  column_width = 1,
  line_height = 1,
  terminal = 0x621000003d00,
  output_data = {
    tty = 0x0,
    x = 0x0,
    w32 = 0x0,
    ns = 0x0,
    pgtk = 0x0,
    haiku = 0x0,
--Type <RET> for more, q to quit, c to continue without paging--
    android = 0x0
  },
  font_driver_list = 0x0,
  desired_cursor = FILLED_BOX_CURSOR,
  cursor_width = 0,
  blink_off_cursor = FILLED_BOX_CURSOR,
  blink_off_cursor_width = 0,
  config_scroll_bar_width = 0,
  config_scroll_bar_cols = 0,
  config_scroll_bar_height = 0,
  config_scroll_bar_lines = 0,
  cost_calculation_baud_rate = 0,
  alpha = {0, 0},
  alpha_background = 0,
  gamma = 0,
  extra_line_spacing = 0,
  background_pixel = 18446744073709551613,
  foreground_pixel = 18446744073709551614
}
(gdb) p SELECTED_FRAME()->output_data
$103 = {
  tty = 0x0,
  x = 0x0,
  w32 = 0x0,
  ns = 0x0,
  pgtk = 0x0,
  haiku = 0x0,
  android = 0x0
}
(gdb) p Vframe_list
$104 = XIL(0x7ffff18f6c63)
(gdb) xlist
$105 = 0x6210000175bd
Lisp_Vectorlike
PVEC_FRAME
$106 = (struct frame *) 0x6210000175b8
"F2"
No symbol "PVEC_TS_QUERY" in current context.
(gdb)


If I run (set redisplay_skip_initial_frame nil), then **everything
works as expected**. It redraws well when I resize the terminal. No
black areas visible.
But I want the root issue; I still want to know why it's ¿wrongly?
classified as initial. And then fix that.


So I think this issue (71343) isn't about X focus (we're dealing with
TTYs anyway); it's about how to react to frame size changes. And right
now it's about why it unexpectedly seems a frame as initial frame.



>
> > It's ok if it can't be fixed. I'm surprised that others didn't have
> > this issue; but maybe not many are running TTY emacs (no X) inside an
> > X window.:
>
> It is a rare and not very interesting situation: users aren't expected
> to kill terminals, they are expected to "C-x #" to close Emacs
> displays.
>

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.

The non-repainting issues described above also happen if I close
emacsclient gracefully by C-x C-c. No killing (SIGHUP, SIGKILL, …) is
needed.

Anyway, it seems the problem may be not in the closing, but in the
resizing+redisplaying of the frame that's left. And in the
initial-frame thing, which I'll keep tracing.




This bug report was last modified 362 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.