From 087b276433ead968f17246956bb7fe435a7e8d23 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Wed, 9 Jul 2025 09:52:01 +0200 Subject: [PATCH] Handle invalid frame_or_window slots in tty input events (Bug#78966) * src/frame.c (make_terminal_frame): Initialize terminal's top_frame slot if it has not been set up yet (Bug#78966). * src/keyboard.c (kbd_buffer_get_event): Do not assume that the event's frame_or_window slot always produces a valid frame (Bug#78966). (tty_read_avail_input): Try to make sure that the input event we create has a valid frame_or_window slot (Bug#78966). Add assertion to that purpose. (cherry picked from commit 2fc402cb0bb62f3c401528246742501a8d42bf14) --- src/frame.c | 9 +++++++++ src/keyboard.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/frame.c b/src/frame.c index 7b2feefc0a3..d256b4fdfbb 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1449,6 +1449,15 @@ make_terminal_frame (struct terminal *terminal, Lisp_Object parent, FRAME_BACKGROUND_PIXEL (f) = FACE_TTY_DEFAULT_BG_COLOR; #endif /* not MSDOS */ + struct tty_display_info *tty = terminal->display_info.tty; + + if (NILP (tty->top_frame)) + /* If this frame's terminal's top frame has not been set up yet, + make the new frame its top frame so the top frame has been set up + before the first do_switch_frame on this terminal happens. See + Bug#78966. */ + tty->top_frame = frame; + #ifdef HAVE_WINDOW_SYSTEM f->vertical_scroll_bar_type = vertical_scroll_bar_none; f->horizontal_scroll_bars = false; diff --git a/src/keyboard.c b/src/keyboard.c index fa0a5fbdd1a..e265db3680b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4237,22 +4237,29 @@ kbd_buffer_get_event (KBOARD **kbp, break; default: { - /* If this event is on a different frame, return a - switch-frame this time, and leave the event in the queue - for next time. */ Lisp_Object frame; Lisp_Object focus; + /* It's not safe to assume that the following will always + produce a valid, live frame (Bug#78966). */ frame = event->ie.frame_or_window; if (CONSP (frame)) frame = XCAR (frame); else if (WINDOWP (frame)) frame = WINDOW_FRAME (XWINDOW (frame)); - focus = FRAME_FOCUS_FRAME (XFRAME (frame)); - if (! NILP (focus)) - frame = focus; + /* If the input focus of this frame is on another frame, + continue with that frame. */ + if (FRAMEP (frame)) + { + focus = FRAME_FOCUS_FRAME (XFRAME (frame)); + if (! NILP (focus)) + frame = focus; + } + /* If this event is on a different frame, return a + switch-frame this time, and leave the event in the queue + for next time. */ if (!EQ (frame, internal_last_event_frame) && !EQ (frame, selected_frame)) obj = make_lispy_switch_frame (frame); @@ -8201,13 +8208,21 @@ tty_read_avail_input (struct terminal *terminal, value of selected_frame is not reliable here, redisplay tends to temporarily change it. However, if the selected frame is a child frame, don't do that since it will cause switch frame - events to switch to the root frame instead. */ - if (FRAME_PARENT_FRAME (XFRAME (selected_frame)) - && (root_frame (XFRAME (selected_frame)) - == XFRAME (tty->top_frame))) + events to switch to the root frame instead. If the tty's top + frame has not been set up yet, always use the selected frame + (Bug#78966). */ + if (!FRAMEP (tty->top_frame) + || (FRAME_PARENT_FRAME (XFRAME (selected_frame)) + && (root_frame (XFRAME (selected_frame)) + == XFRAME (tty->top_frame)))) buf.frame_or_window = selected_frame; else buf.frame_or_window = tty->top_frame; + + /* If neither the selected frame nor the top frame were set, + something must have gone really wrong. */ + eassert (FRAMEP (buf.frame_or_window)); + buf.arg = Qnil; kbd_buffer_store_event (&buf); -- 2.39.5