]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle invalid frame_or_window slots in tty input events (Bug#78966)
authorMartin Rudalics <rudalics@gmx.at>
Wed, 9 Jul 2025 07:52:01 +0000 (09:52 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 24 Jul 2025 07:52:26 +0000 (09:52 +0200)
* 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
src/keyboard.c

index 7b2feefc0a39d93f7e6c00da2fa53d3f6b214898..d256b4fdfbb4dd26775b11544f59d76bb2161a61 100644 (file)
@@ -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;
index fa0a5fbdd1a29b5c5cc9f27db46c407e265fdc3a..e265db3680bea0e1969e2b0929a80e5c86918a08 100644 (file)
@@ -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);