Subject: bug#76406: 31.0.50; Crash with tty child frames

From: martin rudalics <[email-masked]>
Date: Wed, 19 Feb 2025 09:58:46 +0100

> I've build master 849475695a1136ffaefd26c72616ec319da45119 plus your
 > diff on top, which I have attached to the bug report. The build is with
 > checking, --enable-checking=yes,glyphs. Complete config:
 >
 > #define EMACS_CONFIG_OPTIONS "--without-ns --cache-file /var/folders/1d/k_6t25f94sl83szqbf8gpkrh0000gn/T//config.cache.martin --enable-checking=yes,glyphs --with-native-compilation=no CC=clang 'CFLAGS=-Wgnu-imaginary-constant -Wunused-result -g -g -O0 -F /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks -Wno-ignored-attributes -Wno-flag-enum -Wno-missing-method-return-type -Wno-variadic-macros -Wno-strict-prototypes -Wno-availability -Wno-nullability-completeness' --prefix=/Users/gerd/.local"
 >
 > I'm using this as the file to make child frames:
 >
 >
 >
 > The only change compared to your original should be that I load tm.el,
 > activate tm-menu-mode, and use M-g <n> key bindings instead of C-l and
 > so on.
 >
 > With this, emacs -Q, I
 >
 > - open tty-1, tty-2, tty-3 in that order
 >
 > - then I click in the yellow frame
 >
 > - click on the Buffer menu in the menu-bar
 >
 > - click on *Messages*.
 >
 > Effect is a bit strange, some complaints about mouse bindings in the
 > root frame, but no assertion.
 >
 > So I guess I'm missing something important. Any ideas?

Not really: I do the same but positioned the yellow frame more to the
left so that it is not obscured by the other two child frames.  Both
tty-child-frames.el ("/home/martin/temp/tm.el" is my location of your
tm.el) and my patch are attached.  I also attach a screenshot
immediately before clicking on the Buffer menu.  A complete transcript
of the debugging session is below.

This is with master after

commit 0c8abe8bb5072c46a93585cb325c249f85f3d9c2
Author: Jared Finder <[email-masked]>
Date:   Wed Feb 19 09:41:44 2025 +0200

built with

"CFLAGS='-O0 -g3 -no-pie -Wno-missing-braces' ../configure --with-gif=ifavailable --with-tiff=ifavailable --with-gnutls=no --without-pop --enable-checking='yes,glyphs,structs' --enable-check-lisp-object-type=yes"

martin

Current directory is /home/martin/emacs-git/trunk/obj-gtk/src/
GNU gdb (Debian 13.1-3) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
     <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from /home/martin/emacs-git/trunk/obj-gtk/src/emacs...
SIGINT is used by the debugger.
Are you sure you want to change it? (y or n) [answered Y; input not from terminal]
DISPLAY = :0.0
TERM = dumb
Breakpoint 2 at 0x5a2896: file ../../src/xterm.c, line 27098.
(gdb) attach 6872
Attaching to program: /home/martin/emacs-git/trunk/obj-gtk/src/emacs, process 6872
(gdb) Reading symbols from /lib/x86_64-linux-gnu/libtiff.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libtiff.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libjpeg.so.62...
(No debugging symbols found in /lib/x86_64-linux-gnu/libjpeg.so.62)
Reading symbols from /lib/x86_64-linux-gnu/libpng16.so.16...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpng16.so.16)
Reading symbols from /lib/x86_64-linux-gnu/libgif.so.7...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgif.so.7)
Reading symbols from /lib/x86_64-linux-gnu/libwebpdemux.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libwebpdemux.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libwebp.so.7...
(No debugging symbols found in /lib/x86_64-linux-gnu/libwebp.so.7)
Reading symbols from /lib/x86_64-linux-gnu/libgtk-3.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgtk-3.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libgdk-3.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgdk-3.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libz.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libz.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libpango-1.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpango-1.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libharfbuzz.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libharfbuzz.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libcairo.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libcairo.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libgio-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgio-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libgobject-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgobject-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libglib-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libglib-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libSM.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libSM.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libICE.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libICE.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libX11.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libX11.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libX11-xcb.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libX11-xcb.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libxcb.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxcb.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libXrender.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXrender.so.1)
Reading symbols from /lib/x86_64-linux-gnu/librsvg-2.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/librsvg-2.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libm.so.6...
Reading symbols from /usr/lib/debug/.build-id/6d/201df2cb50847f0ed42da4158c3a608d578f03.debug...
Reading symbols from /lib/x86_64-linux-gnu/libdbus-1.so.3...
(No debugging symbols found in /lib/x86_64-linux-gnu/libdbus-1.so.3)
Reading symbols from /lib/x86_64-linux-gnu/libXrandr.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXrandr.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libXinerama.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXinerama.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libXfixes.so.3...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXfixes.so.3)
Reading symbols from /lib/x86_64-linux-gnu/libXext.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXext.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libtinfo.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libtinfo.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libselinux.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libselinux.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libfreetype.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libfreetype.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libfontconfig.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libfontconfig.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libXi.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXi.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libXcomposite.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXcomposite.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libxcb-shape.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxcb-shape.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...
Reading symbols from /usr/lib/debug/.build-id/c0/47672cae7964324658491e7dee26748ae5d2f8.debug...
Reading symbols from /lib/x86_64-linux-gnu/libzstd.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libzstd.so.1)
Reading symbols from /lib/x86_64-linux-gnu/liblzma.so.5...
(No debugging symbols found in /lib/x86_64-linux-gnu/liblzma.so.5)
Reading symbols from /lib/x86_64-linux-gnu/libLerc.so.4...
(No debugging symbols found in /lib/x86_64-linux-gnu/libLerc.so.4)
Reading symbols from /lib/x86_64-linux-gnu/libjbig.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libjbig.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libdeflate.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libdeflate.so.0)
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/f4/bc47db467906580a47640e01e6d901e2642a7b.debug...
Reading symbols from /lib/x86_64-linux-gnu/libgmodule-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgmodule-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libfribidi.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libfribidi.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libcairo-gobject.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libcairo-gobject.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libatk-1.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libatk-1.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libepoxy.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libepoxy.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libxkbcommon.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxkbcommon.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libwayland-client.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libwayland-client.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libwayland-cursor.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libwayland-cursor.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libwayland-egl.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libwayland-egl.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libXcursor.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXcursor.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libXdamage.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXdamage.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libthai.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libthai.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libgraphite2.so.3...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgraphite2.so.3)
Reading symbols from /lib/x86_64-linux-gnu/libpixman-1.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpixman-1.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libxcb-shm.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxcb-shm.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libxcb-render.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxcb-render.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libmount.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libmount.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libffi.so.8...
(No debugging symbols found in /lib/x86_64-linux-gnu/libffi.so.8)
Reading symbols from /lib/x86_64-linux-gnu/libpcre2-8.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libpcre2-8.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libuuid.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libuuid.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libbsd.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libbsd.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libXau.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXau.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libXdmcp.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libXdmcp.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libxml2.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libxml2.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libgcc_s.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgcc_s.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libsystemd.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libsystemd.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libbrotlidec.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libbrotlidec.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libexpat.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libexpat.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libstdc++.so.6...
(No debugging symbols found in /lib/x86_64-linux-gnu/libstdc++.so.6)
Reading symbols from /lib/x86_64-linux-gnu/libdl.so.2...
Reading symbols from /usr/lib/debug/.build-id/55/c2be7202360e34ccf0ad897cae4fa8b88c5e1e.debug...
Reading symbols from /lib/x86_64-linux-gnu/libatspi.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libatspi.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libpthread.so.0...
Reading symbols from /usr/lib/debug/.build-id/fb/4db5e988715b16d1c1ec87fa9e6c2fb5ecbfd8.debug...
Reading symbols from /lib/x86_64-linux-gnu/libdatrie.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libdatrie.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libblkid.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libblkid.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libmd.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libmd.so.0)
Reading symbols from /lib/x86_64-linux-gnu/libicuuc.so.72...
(No debugging symbols found in /lib/x86_64-linux-gnu/libicuuc.so.72)
Reading symbols from /lib/x86_64-linux-gnu/libcap.so.2...
(No debugging symbols found in /lib/x86_64-linux-gnu/libcap.so.2)
Reading symbols from /lib/x86_64-linux-gnu/libgcrypt.so.20...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgcrypt.so.20)
Reading symbols from /lib/x86_64-linux-gnu/liblz4.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/liblz4.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libbrotlicommon.so.1...
(No debugging symbols found in /lib/x86_64-linux-gnu/libbrotlicommon.so.1)
Reading symbols from /lib/x86_64-linux-gnu/libicudata.so.72...
(No debugging symbols found in /lib/x86_64-linux-gnu/libicudata.so.72)
Reading symbols from /lib/x86_64-linux-gnu/libgpg-error.so.0...
(No debugging symbols found in /lib/x86_64-linux-gnu/libgpg-error.so.0)
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
pselect64_syscall (sigmask=0x0, timeout=<optimized out>, exceptfds=0x0, writefds=0x7ffca651e250, readfds=0x7ffca651e2d0, nfds=6) at ../sysdeps/unix/sysv/linux/pselect.c:34
34	../sysdeps/unix/sysv/linux/pselect.c: Datei oder Verzeichnis nicht gefunden.
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x000000000054a281 in FACE_FROM_ID (f=0x17bd59a0, id=11) at ../../src/frame.h:1631
1631	  eassert (0 <= id && id < FRAME_FACE_CACHE (f)->used);
(gdb) bt
#0  0x000000000054a281 in FACE_FROM_ID (f=0x17bd59a0, id=11) at ../../src/frame.h:1631
#1  0x000000000054c6c0 in tty_write_glyphs (f=0x17a6ad50, string=0x7fb15d7dc538, len=40) at ../../src/term.c:793
#2  0x0000000000557e5c in write_glyphs (f=0x17a6ad50, string=0x7fb15d7dc378, len=40) at ../../src/terminal.c:182
#3  0x000000000042de40 in write_row (f=0x17a6ad50, vpos=9, updating_menu_p=false) at ../../src/dispnew.c:6114
#4  0x000000000042be22 in write_matrix (f=0x17a6ad50, inhibit_id_p=true, updating_menu_p=false) at ../../src/dispnew.c:5706
#5  0x0000000000427661 in combine_updates_for_frame (f=0x17a6ad50, inhibit_scrolling=true) at ../../src/dispnew.c:4009
#6  0x000000000047b385 in echo_area_display (update_frame_p=true) at ../../src/xdisp.c:13560
#7  0x0000000000476dbf in message3_nolog (m=XIL(0)) at ../../src/xdisp.c:12458
#8  0x0000000000476a7b in message3 (m=XIL(0)) at ../../src/xdisp.c:12388
#9  0x0000000000476e35 in message1 (m=0x0) at ../../src/xdisp.c:12477
#10 0x00000000006c3a19 in Fmessage (nargs=1, args=0x7fb15a5ff278) at ../../src/editfns.c:3122
#11 0x00000000006d55da in funcall_subr (subr=0x8bf4a0 <Smessage>, numargs=1, args=0x7fb15a5ff278) at ../../src/eval.c:3161
#12 0x00000000007336c2 in exec_byte_code (fun=XIL(0x7fb15aec8cc5), args_template=1025, nargs=4, args=0x7ffca651d5b8) at ../../src/bytecode.c:812
#13 0x00000000006d59f3 in funcall_lambda (fun=XIL(0x7fb15aec8cc5), nargs=4, arg_vector=0x7ffca651d598) at ../../src/eval.c:3229
#14 0x00000000006d4d8f in funcall_general (fun=XIL(0x7fb15aec8cc5), numargs=4, args=0x7ffca651d598) at ../../src/eval.c:3021
#15 0x00000000006d5050 in Ffuncall (nargs=5, args=0x7ffca651d590) at ../../src/eval.c:3070
#16 0x00000000006d44e3 in Fapply (nargs=2, args=0x7ffca651d650) at ../../src/eval.c:2742
#17 0x00000000006d3974 in eval_sub (form=XIL(0x7fb15a5e2783)) at ../../src/eval.c:2547
#18 0x00000000006ce61f in Fprogn (body=XIL(0)) at ../../src/eval.c:439
#19 0x00000000006d01b7 in Flet (args=XIL(0x7fb15a5e0533)) at ../../src/eval.c:1105
#20 0x00000000006d3790 in eval_sub (form=XIL(0x7fb15a5e0523)) at ../../src/eval.c:2526
#21 0x00000000006ce61f in Fprogn (body=XIL(0)) at ../../src/eval.c:439
#22 0x00000000006d5f02 in funcall_lambda (fun=XIL(0x17b31bd5), nargs=5, arg_vector=0x7ffca651db18) at ../../src/eval.c:3327
#23 0x00000000006d4d8f in funcall_general (fun=XIL(0x17b31bd5), numargs=5, args=0x7ffca651db18) at ../../src/eval.c:3021
#24 0x00000000006d5050 in Ffuncall (nargs=6, args=0x7ffca651db10) at ../../src/eval.c:3070
#25 0x00000000006d44e3 in Fapply (nargs=3, args=0x7fb15a5ff1e0) at ../../src/eval.c:2742
#26 0x00000000006d55da in funcall_subr (subr=0x8c0060 <Sapply>, numargs=3, args=0x7fb15a5ff1e0) at ../../src/eval.c:3161
#27 0x00000000007336c2 in exec_byte_code (fun=XIL(0x17ba1bfd), args_template=128, nargs=4, args=0x7fb15a5ff180) at ../../src/bytecode.c:812
#28 0x00000000006d59f3 in funcall_lambda (fun=XIL(0x7fb15b153325), nargs=1, arg_vector=0x7ffca651e400) at ../../src/eval.c:3229
#29 0x00000000006d4d8f in funcall_general (fun=XIL(0x7fb15b153325), numargs=1, args=0x7ffca651e400) at ../../src/eval.c:3021
#30 0x00000000006d5050 in Ffuncall (nargs=2, args=0x7ffca651e3f8) at ../../src/eval.c:3070
#31 0x00000000006c975b in Ffuncall_interactively (nargs=2, args=0x7ffca651e3f8) at ../../src/callint.c:250
#32 0x00000000006d55da in funcall_subr (subr=0x8bf720 <Sfuncall_interactively>, numargs=2, args=0x7ffca651e3f8) at ../../src/eval.c:3161
#33 0x00000000006d4d43 in funcall_general (fun=XIL(0x8bf725), numargs=2, args=0x7ffca651e3f8) at ../../src/eval.c:3017
#34 0x00000000006d5050 in Ffuncall (nargs=3, args=0x7ffca651e3f0) at ../../src/eval.c:3070
#35 0x00000000006cbd8b in Fcall_interactively (function=XIL(0x7fb15a814070), record_flag=XIL(0), keys=XIL(0x7fb15b5c7e55)) at ../../src/callint.c:789
#36 0x00000000006d53da in funcall_subr (subr=0x8bf760 <Scall_interactively>, numargs=3, args=0x7fb15a5ff070) at ../../src/eval.c:3142
#37 0x00000000007336c2 in exec_byte_code (fun=XIL(0x7fb15b5e622d), args_template=1025, nargs=1, args=0x7ffca651f030) at ../../src/bytecode.c:812
#38 0x00000000006d59f3 in funcall_lambda (fun=XIL(0x7fb15b5e622d), nargs=1, arg_vector=0x7ffca651f028) at ../../src/eval.c:3229
#39 0x00000000006d4d8f in funcall_general (fun=XIL(0x7fb15b5e622d), numargs=1, args=0x7ffca651f028) at ../../src/eval.c:3021
#40 0x00000000006d5050 in Ffuncall (nargs=2, args=0x7ffca651f020) at ../../src/eval.c:3070
#41 0x00000000005f3b65 in command_loop_1 () at ../../src/keyboard.c:1545
#42 0x00000000006d11ae in internal_condition_case (bfun=0x5f32f4 <command_loop_1>, handlers=XIL(0x90), hfun=0x5f2776 <cmd_error>) at ../../src/eval.c:1602
#43 0x00000000005f2ebb in command_loop_2 (handlers=XIL(0x90)) at ../../src/keyboard.c:1163
#44 0x00000000006d0618 in internal_catch (tag=XIL(0x12390), func=0x5f2e91 <command_loop_2>, arg=XIL(0x90)) at ../../src/eval.c:1282
#45 0x00000000005f2e4d in command_loop () at ../../src/keyboard.c:1141
#46 0x00000000005f2218 in recursive_edit_1 () at ../../src/keyboard.c:749
#47 0x00000000005f2444 in Frecursive_edit () at ../../src/keyboard.c:832
#48 0x00000000005edc26 in main (argc=5, argv=0x7ffca651f498) at ../../src/emacs.c:2558

Lisp Backtrace:
"message" (0x5a5ff278)
0x5aec8cc0 PVEC_CLOSURE
"apply" (0xa651d650)
"let" (0xa651d940)
"tm--around-popup-menu" (0xa651db18)
"apply" (0x5a5ff1e0)
"popup-menu" (0x5a5ff180)
"menu-bar-open" (0x5a5ff110)
"menu-bar-open-mouse" (0xa651e400)
"funcall-interactively" (0xa651e3f8)
"call-interactively" (0x5a5ff070)
"command-execute" (0xa651f028)
(gdb)

diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index 13911109fd7..1469df6316f 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -2691,53 +2691,74 @@ popup-menu
 			 (filter (when (symbolp map)
 				   (plist-get (get map 'menu-prop) :filter))))
 		    (if filter (funcall filter (symbol-function map)) map)))))
-	 (frame (selected-frame))
+	 (selected-frame (selected-frame))
+	 (frame (if (and (eq (framep selected-frame) t) (frame-parent)
+			 from-menu-bar
+			 (zerop (or (frame-parameter nil 'menu-bar-lines) 0)))
+		    ;; If the selected frame is a tty child frame
+		    ;; without its own menu bar and we are called from
+		    ;; the menu bar, the menu bar must be on the root
+		    ;; frame of the selected frame.
+		    (frame-root-frame)
+		  (selected-frame)))
 	 event cmd)
-    (if from-menu-bar
-	(let* ((xy (posn-x-y position))
-	       (menu-symbol (menu-bar-menu-at-x-y (car xy) (cdr xy))))
-	  (setq position (list menu-symbol (list frame '(menu-bar)
-						 xy 0))))
-      (setq position (popup-menu-normalize-position position)))
-    ;; The looping behavior was taken from lmenu's popup-menu-popup
-    (while (and map (setq event
-			  ;; map could be a prefix key, in which case
-			  ;; we need to get its function cell
-			  ;; definition.
-			  (x-popup-menu position (indirect-function map))))
-      ;; Strangely x-popup-menu returns a list.
-      ;; mouse-major-mode-menu was using a weird:
-      ;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
-      (setq cmd
-	    (cond
-	     ((and from-menu-bar
-		   (consp event)
-		   (numberp (car event))
-		   (numberp (cdr event)))
-	      (let ((x (car event))
-		    (y (cdr event))
-		    menu-symbol)
-		(setq menu-symbol (menu-bar-menu-at-x-y x y))
-		(setq position (list menu-symbol (list frame '(menu-bar)
-						 event 0)))
-		(setq map
-		      (key-binding (vector 'menu-bar menu-symbol)))))
-	     ((and (not (keymapp map)) (listp map))
-	      ;; We were given a list of keymaps.  Search them all
-	      ;; in sequence until a first binding is found.
-	      (let ((mouse-click (apply 'vector event))
-		    binding)
-		(while (and map (null binding))
-		  (setq binding (lookup-key-ignore-too-long (car map) mouse-click))
-		  (setq map (cdr map)))
-                binding))
-	     (t
-	      ;; We were given a single keymap.
-	      (lookup-key map (apply 'vector event)))))
-      ;; Clear out echoing, which perhaps shows a prefix arg.
-      (message "")
-      ;; Maybe try again but with the submap.
-      (setq map (if (keymapp cmd) cmd)))
+    (with-selected-frame frame
+      (if from-menu-bar
+	  (let* ((xy (posn-x-y position))
+		 (menu-symbol (menu-bar-menu-at-x-y (car xy) (cdr xy))))
+	    (setq position (list menu-symbol (list frame '(menu-bar)
+						   xy 0))))
+	(setq position (popup-menu-normalize-position position)))
+
+      ;; The looping behavior was taken from lmenu's popup-menu-popup
+      (while (and map (setq event
+			    ;; map could be a prefix key, in which case
+			    ;; we need to get its function cell
+			    ;; definition.
+			    (x-popup-menu position (indirect-function map))))
+	;; Strangely x-popup-menu returns a list.
+	;; mouse-major-mode-menu was using a weird:
+	;; (key-binding (apply 'vector (append '(menu-bar) menu-prefix events)))
+	(setq cmd
+	      (cond
+	       ((and from-menu-bar
+		     (consp event)
+		     (numberp (car event))
+		     (numberp (cdr event)))
+		(let ((x (car event))
+		      (y (cdr event))
+		      menu-symbol)
+		  (setq menu-symbol (menu-bar-menu-at-x-y x y))
+		  (setq position (list menu-symbol (list frame '(menu-bar)
+							 event 0)))
+		  (if (not (eq frame selected-frame))
+		      ;; If we are using the menu bar from the root
+		      ;; frame, look up the key binding in the keymaps
+		      ;; of the initially selected window's buffer to
+		      ;; make sure that navigating the menu bar with the
+		      ;; keyboard works as intended.
+		      (setq map
+			    (key-binding (vector 'menu-bar menu-symbol) nil nil
+					 (frame-selected-window selected-frame)))
+		    (setq map
+			  (key-binding (vector 'menu-bar menu-symbol))))))
+	       ((and (not (keymapp map)) (listp map))
+		;; We were given a list of keymaps.  Search them all
+		;; in sequence until a first binding is found.
+		(let ((mouse-click (apply 'vector event))
+		      binding)
+		  (while (and map (null binding))
+		    (setq binding (lookup-key-ignore-too-long (car map) mouse-click))
+		    (setq map (cdr map)))
+		  binding))
+	       (t
+		;; We were given a single keymap.
+		(lookup-key map (apply 'vector event)))))
+	;; Clear out echoing, which perhaps shows a prefix arg.
+	(message "")
+	;; Maybe try again but with the submap.
+	(setq map (if (keymapp cmd) cmd))))
+
     ;; If the user did not cancel by refusing to select,
     ;; and if the result is a command, run it.
     (when (and (null map) (commandp cmd))
@@ -2808,14 +2829,27 @@ menu-bar-open
 If FRAME is nil or not given, use the selected frame."
   (interactive
    (list nil (prefix-numeric-value current-prefix-arg)))
-  (let ((type (framep (or frame (selected-frame)))))
+  (let* ((type (framep (or frame (selected-frame))))
+	 root
+	 (frame (if (and (eq type t) (frame-parent frame)
+			 (null tty-menu-open-use-tmm)
+			 (zerop (or (frame-parameter frame 'menu-bar-lines) 0))
+			 (setq root (frame-root-frame))
+			 (not (zerop
+			       (or (frame-parameter root 'menu-bar-lines) 0))))
+		    ;; If FRAME is a tty child frame without its own
+		    ;; menu bar, 'tty-menu-open-use-tmm' is false and
+		    ;; FRAME's root frame has a menu bar, use that root
+		    ;; frame's menu bar.
+		    root
+		  frame)))
     (cond
      ((eq type 'x) (x-menu-bar-open frame))
      ((eq type 'w32) (w32-menu-bar-open frame))
      ((eq type 'haiku) (haiku-menu-bar-open frame))
      ((eq type 'pgtk) (pgtk-menu-bar-open frame))
      ((and (null tty-menu-open-use-tmm)
-	   (not (zerop (or (frame-parameter nil 'menu-bar-lines) 0))))
+	   (not (zerop (or (frame-parameter frame 'menu-bar-lines) 0))))
       ;; Make sure the menu bar is up to date.  One situation where
       ;; this is important is when this function is invoked by name
       ;; via M-x, in which case the menu bar includes the "Minibuf"
@@ -2831,7 +2865,7 @@ menu-bar-open
                       (current-local-map) (vector 'menu-bar menu))
 		     (cdar (minor-mode-key-binding (vector 'menu-bar menu)))
                      (mouse-menu-bar-map))
-		    (posn-at-x-y x 0 nil t) nil t)))
+		    (posn-at-x-y x 0 frame t) nil t)))
      (t (with-selected-frame (or frame (selected-frame))
           (tmm-menubar))))))
 
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 1f0ca6a51b6..e3e13f03d9b 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1111,7 +1111,10 @@ mouse-drag-frame-resize
 	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
 	 ;; Initial "first" mouse position.  While dragging we base all
 	 ;; calculations against that position.
-	 (first-x-y (mouse-absolute-pixel-position))
+	 (tty (tty-type frame))
+	 (first-x-y (if tty
+			(mouse-position-in-root-frame)
+		      (mouse-absolute-pixel-position)))
          (first-x (car first-x-y))
          (first-y (cdr first-x-y))
          (exitfun nil)
@@ -1119,7 +1122,9 @@ mouse-drag-frame-resize
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (let* ((last-x-y (mouse-absolute-pixel-position))
+              (let* ((last-x-y (if tty
+				   (mouse-position-in-root-frame)
+				 (mouse-absolute-pixel-position)))
 		     (last-x (car last-x-y))
 		     (last-y (cdr last-x-y))
 		     (left (- last-x first-x))
@@ -1228,10 +1233,13 @@ mouse-drag-frame-move
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
 	 ;; Initial "first" mouse position.  While dragging we base all
 	 ;; calculations against that position.
-	 (first-x-y (mouse-absolute-pixel-position))
-         (first-x (car first-x-y))
-         (first-y (cdr first-x-y))
-         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+	 (tty (tty-type frame))
+	 (first-x-y (if tty
+			(mouse-position-in-root-frame)
+		      (mouse-absolute-pixel-position)))
+	 (first-x (car first-x-y))
+	 (first-y (cdr first-x-y))
+	 ;; `snap-width' (maybe also a yet to be provided `snap-height')
          ;; could become floats to handle proportionality wrt PARENT.
          ;; We don't do any checks on this parameter so far.
          (snap-width (frame-parameter frame 'snap-width))
@@ -1247,7 +1255,9 @@ mouse-drag-frame-move
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (let* ((last-x-y (mouse-absolute-pixel-position))
+              (let* ((last-x-y (if tty
+				   (mouse-position-in-root-frame)
+				 (mouse-absolute-pixel-position)))
 		     (last-x (car last-x-y))
 		     (last-y (cdr last-x-y))
 		     (left (- last-x first-x))
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 250f4efebb4..6f33c65ff2a 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -304,19 +304,36 @@ xterm-mouse-event
              (x (or (nth 1 frame-and-xy) x))
              (y (or (nth 2 frame-and-xy) y))
              (w (window-at x y frame))
-             (ltrb (window-edges w))
-             (left (nth 0 ltrb))
-             (top (nth 1 ltrb))
-             (posn (if w
-		       (posn-at-x-y (- x left) (- y top) w t)
-		     (append (list nil (if (and tab-bar-mode
-                                                (or (not menu-bar-mode)
-                                                    ;; The tab-bar is on the
-                                                    ;; second row below menu-bar
-                                                    (eq y 1)))
-                                           'tab-bar
-                                         'menu-bar))
-                             (nthcdr 2 (posn-at-x-y x y (selected-frame))))))
+             (posn
+	      (if w
+		  (let* ((ltrb (window-edges w))
+			 (left (nth 0 ltrb))
+			 (top (nth 1 ltrb)))
+		    (posn-at-x-y (- x left) (- y top) w t))
+		(let ((item (cond
+                             ((and menu-bar-mode (eq y 0))
+                              'menu-bar)
+			     ((and tab-bar-mode
+				   (or (and menu-bar-mode
+					    (eq y 1))
+				       (eq y 0)))
+                              'tab-bar)
+			     ((eq x -1)
+			      (cond
+			       ((eq y -1) 'top-left-corner)
+			       ((eq y (frame-height frame)) 'bottom-left-corner)
+			       (t 'left-edge)))
+			     ((eq x (frame-width frame))
+			      (cond
+			       ((eq y -1) 'top-right-corner)
+			       ((eq y (frame-height frame)) 'bottom-right-corner)
+			       (t 'right-edge)))
+			     ((eq y -1) 'top-edge)
+			     (t 'bottom-edge))))
+		  (append (list (unless (memq item '(menu-bar tab-bar))
+				  frame)
+				item)
+			  (nthcdr 2 (posn-at-x-y x y (selected-frame)))))))
              (event (list type posn)))
         (setcar (nthcdr 3 posn) timestamp)
 
diff --git a/src/frame.c b/src/frame.c
index bcf11e25222..40c8eff1bb9 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -1482,17 +1482,39 @@ get_future_frame_param (Lisp_Object parameter,
 #endif
 
 int
-tty_child_pos_param (struct frame *child, Lisp_Object key,
-		     Lisp_Object params, int dflt)
+tty_child_pos_param (struct frame *f, Lisp_Object key,
+		     Lisp_Object params, int pos)
 {
+  struct frame *p = XFRAME (f->parent_frame);
   Lisp_Object val = Fassq (key, params);
+
   if (CONSP (val))
     {
       val = XCDR (val);
-      if (FIXNUMP (val))
-	return XFIXNUM (val);
+
+      if (TYPE_RANGED_FIXNUMP (int, val))
+	{
+	  pos = XFIXNUM (val);
+
+	  if (pos < 0)
+	    /* Handle negative value. */
+	    pos = (EQ (key, Qtop)
+		   ? p->pixel_height - f->pixel_height + pos
+		   : p->pixel_width - f->pixel_width + pos);
+	}
+      else if (CONSP (val) && EQ (XCAR (val), Qplus)
+	       && CONSP (XCDR (val))
+	       && TYPE_RANGED_FIXNUMP (int, XCAR (XCDR (val))))
+	pos = XFIXNUM (XCAR (XCDR (val)));
+      else if (CONSP (val) && EQ (XCAR (val), Qminus)
+	       && CONSP (XCDR (val))
+	       && RANGED_FIXNUMP (-INT_MAX, XCAR (XCDR (val)), INT_MAX))
+	pos = (EQ (key, Qtop)
+	       ? p->pixel_height - f->pixel_height - XFIXNUM (XCAR (XCDR (val)))
+	       : p->pixel_width - f->pixel_width - XFIXNUM (XCAR (XCDR (val))));
     }
-  return dflt;
+
+  return pos;
 }
 
 int
@@ -2866,7 +2888,7 @@ DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 2, "",
   return delete_frame (frame, !NILP (force) ? Qt : Qnil);
 }
 
-#ifdef HAVE_WINDOW_SYSTEM
+
 /**
  * frame_internal_border_part:
  *
@@ -2889,7 +2911,11 @@ DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 2, "",
 enum internal_border_part
 frame_internal_border_part (struct frame *f, int x, int y)
 {
-  int border = FRAME_INTERNAL_BORDER_WIDTH (f);
+  int border = (FRAME_INTERNAL_BORDER_WIDTH (f)
+		? FRAME_INTERNAL_BORDER_WIDTH (f)
+		: (is_tty_child_frame (f) && !FRAME_UNDECORATED (f))
+		? 1
+		: 0);
   int offset = FRAME_LINE_HEIGHT (f);
   int width = FRAME_PIXEL_WIDTH (f);
   int height = FRAME_PIXEL_HEIGHT (f);
@@ -2958,7 +2984,7 @@ frame_internal_border_part (struct frame *f, int x, int y)
 
   return part;
 }
-#endif
+
 
 /* Return mouse position in character cell units.  */
 
@@ -6513,6 +6539,36 @@ DEFUN ("frame-pointer-visible-p", Fframe_pointer_visible_p,
   return decode_any_frame (frame)->pointer_invisible ? Qnil : Qt;
 }
 
+DEFUN ("mouse-position-in-root-frame", Fmouse_position_in_root_frame,
+       Smouse_position_in_root_frame, 0, 0, 0,
+       doc: /* Return mouse position in selected frame's root frame.
+Return the position of `mouse-position' in coordinates of the root frame
+of the frame returned by 'mouse-position'.  */)
+  (void)
+{
+  Lisp_Object pos = mouse_position (true);
+  Lisp_Object frame = XCAR (pos);
+  struct frame *f = XFRAME (frame);
+  int x = XFIXNUM (XCAR (XCDR (pos))) + f->left_pos;
+  int y = XFIXNUM (XCDR (XCDR (pos))) + f->top_pos;
+
+  if (!FRAMEP (frame))
+    return Qnil;
+  else
+    {
+      f = FRAME_PARENT_FRAME (f);
+
+      while (f)
+	{
+	  x = x + f->left_pos;
+	  y = y + f->top_pos;
+	  f = FRAME_PARENT_FRAME (f);
+	}
+
+      return Fcons (make_fixnum (x), make_fixnum (y));
+    }
+}
+
 DEFUN ("frame--set-was-invisible", Fframe__set_was_invisible,
        Sframe__set_was_invisible, 2, 2, 0,
        doc: /* Set FRAME's was-invisible flag if WAS-INVISIBLE is non-nil.
@@ -7285,6 +7341,7 @@ focus (where a frame immediately loses focus when it's left by the mouse
   defsubr (&Sframe_position);
   defsubr (&Sset_frame_position);
   defsubr (&Sframe_pointer_visible_p);
+  defsubr (&Smouse_position_in_root_frame);
   defsubr (&Sframe__set_was_invisible);
   defsubr (&Sframe_window_state_change);
   defsubr (&Sset_frame_window_state_change);
diff --git a/src/frame.h b/src/frame.h
index c9cc65e597d..e27021fa283 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -31,6 +31,19 @@ #define EMACS_FRAME_H
   vertical_scroll_bar_right
 };
 
+enum internal_border_part
+  {
+   INTERNAL_BORDER_NONE,
+   INTERNAL_BORDER_LEFT_EDGE,
+   INTERNAL_BORDER_TOP_LEFT_CORNER,
+   INTERNAL_BORDER_TOP_EDGE,
+   INTERNAL_BORDER_TOP_RIGHT_CORNER,
+   INTERNAL_BORDER_RIGHT_EDGE,
+   INTERNAL_BORDER_BOTTOM_RIGHT_CORNER,
+   INTERNAL_BORDER_BOTTOM_EDGE,
+   INTERNAL_BORDER_BOTTOM_LEFT_CORNER,
+  };
+
 #ifdef HAVE_WINDOW_SYSTEM
 
 enum fullscreen_type
@@ -53,19 +66,6 @@ #define EMACS_FRAME_H
   z_group_above_suspended,
 };
 
-enum internal_border_part
-  {
-   INTERNAL_BORDER_NONE,
-   INTERNAL_BORDER_LEFT_EDGE,
-   INTERNAL_BORDER_TOP_LEFT_CORNER,
-   INTERNAL_BORDER_TOP_EDGE,
-   INTERNAL_BORDER_TOP_RIGHT_CORNER,
-   INTERNAL_BORDER_RIGHT_EDGE,
-   INTERNAL_BORDER_BOTTOM_RIGHT_CORNER,
-   INTERNAL_BORDER_BOTTOM_EDGE,
-   INTERNAL_BORDER_BOTTOM_LEFT_CORNER,
-  };
-
 #ifdef NS_IMPL_COCOA
 enum ns_appearance_type
   {
@@ -1862,7 +1862,6 @@ #define EMACS_CLASS "Emacs"
 extern void set_frame_menubar (struct frame *f, bool deep_p);
 extern void frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y);
 extern void free_frame_menubar (struct frame *);
-extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y);
 
 #if defined HAVE_X_WINDOWS
 extern void x_wm_set_icon_position (struct frame *, int, int);
@@ -1888,6 +1887,8 @@ gui_set_bitmap_icon (struct frame *f)
 #endif /* !HAVE_NS */
 #endif /* HAVE_WINDOW_SYSTEM */
 
+extern enum internal_border_part frame_internal_border_part (struct frame *f,
+							     int x, int y);
 extern bool frame_ancestor_p (struct frame *af, struct frame *df);
 
 INLINE void
diff --git a/src/keyboard.c b/src/keyboard.c
index b22814d702d..5167b3ce5ad 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -5553,7 +5553,6 @@ #define ISO_FUNCTION_KEY_OFFSET 0xfe00
   SYMBOL_INDEX (Qrightmost), SYMBOL_INDEX (Qend_scroll), SYMBOL_INDEX (Qratio)
 };
 
-#ifdef HAVE_WINDOW_SYSTEM
 /* An array of symbol indexes of internal border parts, indexed by an enum
    internal_border_part value.  Note that Qnil corresponds to
    internal_border_part_none and should not appear in Lisp events.  */
@@ -5564,7 +5563,6 @@ #define ISO_FUNCTION_KEY_OFFSET 0xfe00
   SYMBOL_INDEX (Qbottom_right_corner), SYMBOL_INDEX (Qbottom_edge),
   SYMBOL_INDEX (Qbottom_left_corner)
 };
-#endif
 
 /* A vector, indexed by button number, giving the down-going location
    of currently depressed buttons, both scroll bar and non-scroll bar.
@@ -5599,6 +5597,90 @@ #define ISO_FUNCTION_KEY_OFFSET 0xfe00
 
 static int double_click_count;
 
+enum frame_border_side
+{
+  ON_LEFT,
+  ON_TOP,
+  ON_RIGHT,
+  ON_BOTTOM,
+  ON_NONE
+};
+
+/* Handle make_lispy_event when a tty child frame's decorations shall be
+   used in lieu of internal borders.  R denotes the root frame under
+   investigation, MX and MY are the positions of the mouse relative to
+   R.  WINDOW_OR_FRAME denotes the frame previously reported as the
+   frame under (MX, MY).  Note: The decorations of a child frame are
+   always drawn outside the child frame, so WINDOW_OR_FRAME is certainly
+   not the frame we are looking for.  Neither is R.  A candidate frame
+   is any frame but WINDOW_OR_FRAME and R whose root is R, which is not
+   decorated and has a 'drag-internal-border' parameter.  If we find a
+   suitable frame, set WINDOW_OR_FRAME to it and POSN to the part of the
+   internal border corresponding to (MX, MY) on the frame found.  */
+
+static void
+make_lispy_tty_position (struct frame *r, int mx, int my,
+			 Lisp_Object *window_or_frame, Lisp_Object *posn)
+{
+  enum frame_border_side side = ON_NONE;
+  struct frame *f = NULL;
+  Lisp_Object tail, frame;
+  int ix, iy = 0;
+
+  FOR_EACH_FRAME (tail, frame)
+    {
+      f = XFRAME (frame);
+
+      int left = f->left_pos;
+      int top = f->top_pos;
+      int right = left + f->pixel_width;
+      int bottom = top + f->pixel_height;
+
+      if (root_frame (f) == r && f != r
+	  && !FRAME_UNDECORATED (f)
+	  && !NILP (get_frame_param (f, Qdrag_internal_border)))
+	{
+	  if (left == mx + 1 && my >= top && my <= bottom)
+	    {
+	      side = ON_LEFT;
+	      ix = -1;
+	      iy = my - top + 1;
+	      break;
+	    }
+	  else if (right == mx && my >= top && my <= bottom)
+	    {
+	      side = ON_RIGHT;
+	      ix = f->pixel_width;
+	      iy = my - top + 1;
+	      break;
+	    }
+	  else if (top == my + 1 && mx >= left && mx <= right)
+	    {
+	      side = ON_TOP;
+	      ix = mx - left + 1;
+	      iy = -1;
+	      break;
+	    }
+	  else if (bottom == my && mx >= left && mx <= right)
+	    {
+	      side = ON_BOTTOM;
+	      ix = mx - left + 1;
+	      iy = f->pixel_height;
+	      break;
+	    }
+	}
+    }
+
+  if (side != ON_NONE)
+    {
+      enum internal_border_part part
+	= frame_internal_border_part (f, ix, iy);
+
+      XSETFRAME (*window_or_frame, f);
+      *posn = builtin_lisp_symbol (internal_border_parts[part]);
+    }
+}
+
 /* X and Y are frame-relative coordinates for a click or wheel event.
    Return a Lisp-style event list.  */
 
@@ -5677,7 +5759,14 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
       window_or_frame = Qnil;	/* see above */
     }
 
-  if (WINDOWP (window_or_frame))
+  if (WINDOWP (window_or_frame) && is_tty_frame (f)
+      && (is_tty_root_frame_with_visible_child (f)
+	  || is_tty_child_frame (f)))
+    make_lispy_tty_position (root_frame (f), mx, my, &window_or_frame, &posn);
+
+  if (!NILP (posn))
+    ;
+  else if (WINDOWP (window_or_frame))
     {
       /* It's a click in window WINDOW at frame coordinates (X,Y)  */
       struct window *w = XWINDOW (window_or_frame);
@@ -5880,9 +5969,7 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
       xret = mx;
       yret = my;
 
-#ifdef HAVE_WINDOW_SYSTEM
-      if (FRAME_WINDOW_P (f)
-	  && FRAME_LIVE_P (f)
+      if (FRAME_LIVE_P (f)
 	  && NILP (posn)
 	  && FRAME_INTERNAL_BORDER_WIDTH (f) > 0
 	  && !NILP (get_frame_param (f, Qdrag_internal_border)))
@@ -5892,7 +5979,6 @@ make_lispy_position (struct frame *f, Lisp_Object x, Lisp_Object y,
 
 	  posn = builtin_lisp_symbol (internal_border_parts[part]);
 	}
-#endif
     }
   else
     {
@@ -12572,7 +12658,9 @@ DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
      into the left fringe.  */
   if (XFIXNUM (x) != -1)
     CHECK_FIXNAT (x);
-  CHECK_FIXNAT (y);
+  CHECK_FIXNUM (y);
+  if (XFIXNUM (y) != -1)
+    CHECK_FIXNAT (y);
 
   if (NILP (frame_or_window))
     frame_or_window = selected_window;
diff --git a/src/keymap.c b/src/keymap.c
index bc731c54ef0..2c250578b00 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -1652,7 +1652,8 @@ DEFUN ("current-active-maps", Fcurrent_active_maps, Scurrent_active_maps,
        doc: /* Return a list of the currently active keymaps.
 OLP if non-nil indicates that we should obey `overriding-local-map' and
 `overriding-terminal-local-map'.  POSITION can specify a click position
-like in the respective argument of `key-binding'.  */)
+like in the respective argument of `key-binding' or a live window which
+means to return the active maps for that window's buffer.  */)
   (Lisp_Object olp, Lisp_Object position)
 {
   specpdl_ref count = SPECPDL_INDEX ();
@@ -1682,6 +1683,16 @@ DEFUN ("current-active-maps", Fcurrent_active_maps, Scurrent_active_maps,
 	  set_buffer_internal (XBUFFER (XWINDOW (window)->contents));
 	}
     }
+  else if (WINDOW_LIVE_P (position))
+    {
+      if (BUFFERP (XWINDOW (position)->contents)
+	  && XBUFFER (XWINDOW (position)->contents) != current_buffer)
+	{
+	  /* See comment above.  */
+	  record_unwind_current_buffer ();
+	  set_buffer_internal (XBUFFER (XWINDOW (position)->contents));
+	}
+    }
 
   if (!NILP (olp)
       /* The doc said that overriding-terminal-local-map should
diff --git a/src/term.c b/src/term.c
index fd95e75a007..2ef763d0ffc 100644
--- a/src/term.c
+++ b/src/term.c
@@ -2658,12 +2658,68 @@ tty_frame_at (int x, int y, int *cx, int *cy)
       Lisp_Object frame = Fcar (frames);
       struct frame *f = XFRAME (frame);
       int fx, fy;
+      bool on_border = false;
+
       root_xy (f, 0, 0, &fx, &fy);
 
-      if ((fx <= x && x < fx + f->pixel_width)
-	  && (fy <= y && y < fy + f->pixel_height))
+      if (!FRAME_UNDECORATED (f) && FRAME_PARENT_FRAME (f))
+	{
+	  if (fy - 1 <= y && y <= fy + f->pixel_height + 1)
+	    {
+	      if (fx == x + 1)
+		{
+		  *cx = -1;
+		  on_border = true;
+		}
+	      else if (fx + f->pixel_width == x)
+		{
+		  *cx = f->pixel_width;
+		  on_border = true;
+		}
+
+	      if (on_border)
+		{
+		  *cy = y - fy;
+
+		  return frame;
+		}
+	    }
+
+	  if (fx - 1 <= x && x <= fx + f->pixel_width + 1)
+	    {
+	      if (fy == y + 1)
+		{
+		  *cy = -1;
+		  on_border = true;
+		}
+	      else if (fy + f->pixel_height == y)
+		{
+		  *cy = f->pixel_height;
+		  on_border = true;
+		}
+
+	      if (on_border)
+		{
+		  *cx = x - fx;
+
+		  return frame;
+		}
+	    }
+
+
+	  if ((fx <= x && x <= fx + f->pixel_width)
+	      && (fy <= y && y <= fy + f->pixel_height))
+	    {
+	      child_xy (XFRAME (frame), x, y, cx, cy);
+
+	      return frame;
+	    }
+	}
+      else if ((fx <= x && x <= fx + f->pixel_width)
+	       && (fy <= y && y <= fy + f->pixel_height))
 	{
 	  child_xy (XFRAME (frame), x, y, cx, cy);
+
 	  return frame;
 	}
     }
@@ -2673,7 +2729,7 @@ tty_frame_at (int x, int y, int *cx, int *cy)
 }
 
 DEFUN ("tty-frame-at", Ftty_frame_at, Stty_frame_at, 2, 2, 0,
-       doc : /* Return tty frame containing absolute pixel position (X, Y).
+       doc: /* Return tty frame containing absolute pixel position (X, Y).
 Value is nil if no frame found.  Otherwise it is a list (FRAME CX CY),
 where FRAME is the frame containing (X, Y) and CX and CY are X and Y
 relative to FRAME.  */)
@@ -2687,6 +2743,7 @@ DEFUN ("tty-frame-at", Ftty_frame_at, Stty_frame_at, 2, 2, 0,
   Lisp_Object frame = tty_frame_at (XFIXNUM (x), XFIXNUM (y), &cx, &cy);
   if (NILP (frame))
     return Qnil;
+
   return list3 (frame, make_fixnum (cx), make_fixnum (cy));
 }
 
diff --git a/src/window.c b/src/window.c
index 330a95a716f..1ac004af5e0 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1758,6 +1758,13 @@ DEFUN ("window-at", Fwindow_at, Swindow_at, 2, 3, 0,
 {
   struct frame *f = decode_live_frame (frame);
 
+  CHECK_INTEGER (x);
+  CHECK_INTEGER (y);
+
+  if (XFIXNUM (x) < 0 || XFIXNUM (x) > FRAME_PIXEL_WIDTH (f)
+      || XFIXNUM (y) < 0 || XFIXNUM (y) > FRAME_PIXEL_HEIGHT (f))
+    return Qnil;
+
   CHECK_NUMBER (x);
   CHECK_NUMBER (y);
 
diff --git a/src/xdisp.c b/src/xdisp.c
index 7a164ba2972..335ed4752f6 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -1147,7 +1147,7 @@ #define THIN_SPACE_WIDTH 1
 				 struct glyph_matrix *, ptrdiff_t, ptrdiff_t,
 				 int, int);
 static bool cursor_row_fully_visible_p (struct window *, bool, bool, bool);
-static bool update_menu_bar (struct frame *, bool, bool);
+static bool update_menu_bar (struct frame *, bool, bool, struct window *);
 static bool try_window_reusing_current_matrix (struct window *);
 static int try_window_id (struct window *);
 static void maybe_produce_line_number (struct it *);
@@ -14064,13 +14064,32 @@ prepare_menu_bars (void)
       /* True means that update_menu_bar has run its hooks
 	 so any further calls to update_menu_bar shouldn't do so again.  */
       bool menu_bar_hooks_run = false;
+      struct window *sw = XWINDOW (selected_window);
+      struct frame *sf = WINDOW_XFRAME (sw);
+      struct frame *rf = NULL;
+
+      if (FRAME_PARENT_FRAME (sf) && !FRAME_WINDOW_P (sf)
+	  && FRAME_MENU_BAR_LINES (sf) == 0
+	  && FRAME_MENU_BAR_LINES (rf = root_frame (sf)) != 0
+	  && NILP (Fdefault_value (Qtty_menu_open_use_tmm)))
+	/* If the selected window's frame is a tty child frame without
+	   menu bar, that frame's root frame has a menu bar and
+	   'tty-menu-open-use-tmm' is nil, update the menu bar of the
+	   root frame from the selected window.  */
+	sf = rf;
+      else
+	{
+	  sf = NULL;
+	  sw = NULL;
+	}
 
       record_unwind_save_match_data ();
 
       FOR_EACH_FRAME (tail, frame)
 	{
 	  struct frame *f = XFRAME (frame);
-	  struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+	  struct window *w
+	    = sf == f ? sw : XWINDOW (FRAME_SELECTED_WINDOW (f));
 
 	  /* Ignore tooltip frame.  */
 	  if (FRAME_TOOLTIP_P (f))
@@ -14082,8 +14101,8 @@ prepare_menu_bars (void)
 	      && !XBUFFER (w->contents)->text->redisplay)
 	    continue;
 
-	  if (!FRAME_PARENT_FRAME (f))
-	    menu_bar_hooks_run = update_menu_bar (f, false, menu_bar_hooks_run);
+	  menu_bar_hooks_run
+	    = update_menu_bar (f, false, menu_bar_hooks_run, w);
 
 	  update_tab_bar (f, false);
 #ifdef HAVE_WINDOW_SYSTEM
@@ -14095,10 +14114,21 @@ prepare_menu_bars (void)
     }
   else
     {
-      struct frame *sf = SELECTED_FRAME ();
+      struct window *sw = XWINDOW (selected_window);
+      struct frame *sf = WINDOW_XFRAME (sw);
+      struct frame *rf = NULL;
 
-      if (!FRAME_PARENT_FRAME (sf))
-	update_menu_bar (sf, true, false);
+      if (FRAME_PARENT_FRAME (sf) && !FRAME_WINDOW_P (sf)
+	  && FRAME_MENU_BAR_LINES (sf) == 0
+	  && FRAME_MENU_BAR_LINES (rf = root_frame (sf)) != 0
+	  && NILP (Fdefault_value (Qtty_menu_open_use_tmm)))
+	/* If the selected window's frame is a tty child frame without
+	   menu bar, that frame's root frame has a menu bar and
+	   'tty-menu-open-use-tmm' is nil, update the menu bar of the
+	   root frame from the selected window.  */
+	sf = rf;
+
+      update_menu_bar (sf, true, false, sw);
 
       update_tab_bar (sf, true);
 #ifdef HAVE_WINDOW_SYSTEM
@@ -14120,20 +14150,14 @@ prepare_menu_bars (void)
    updated value of this flag, to pass to the next call.  */
 
 static bool
-update_menu_bar (struct frame *f, bool save_match_data, bool hooks_run)
+update_menu_bar (struct frame *f, bool save_match_data, bool hooks_run, struct window *w)
 {
-  Lisp_Object window;
-  struct window *w;
-
   /* If called recursively during a menu update, do nothing.  This can
      happen when, for instance, an activate-menubar-hook causes a
      redisplay.  */
   if (inhibit_menubar_update)
     return hooks_run;
 
-  window = FRAME_SELECTED_WINDOW (f);
-  w = XWINDOW (window);
-
   if (FRAME_WINDOW_P (f)
       ?
 #ifdef HAVE_EXT_MENU_BAR
@@ -21090,24 +21114,33 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 
   /* When we reach a frame's selected window, redo the frame's menu
      bar, tool bar, tab-bar, and the frame's title.  */
-  if (update_mode_line
-      && EQ (FRAME_SELECTED_WINDOW (f), window))
+  if (update_mode_line && EQ (FRAME_SELECTED_WINDOW (f), window))
     {
-      bool redisplay_menu_p;
-
       if (FRAME_WINDOW_P (f))
 	{
 #ifdef HAVE_EXT_MENU_BAR
-	  redisplay_menu_p = FRAME_EXTERNAL_MENU_BAR (f);
+	  if (FRAME_EXTERNAL_MENU_BAR (f))
+	    display_menu_bar (w);
 #else
-	  redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
+	  if (FRAME_MENU_BAR_LINES (f) > 0)
+	    display_menu_bar (w);
 #endif
 	}
       else
-        redisplay_menu_p = FRAME_MENU_BAR_LINES (f) > 0;
+	{
+	  struct frame *rf = NULL;
 
-      if (redisplay_menu_p)
-        display_menu_bar (w);
+	  if (FRAME_PARENT_FRAME (f)
+	      && FRAME_MENU_BAR_LINES (f) == 0
+	      && FRAME_MENU_BAR_LINES (rf = root_frame (f)) != 0
+	      && NILP (Fdefault_value (Qtty_menu_open_use_tmm)))
+	    /* If F is a tty child frame without menu bar, that frame's root
+	       frame has a menu bar and 'tty-menu-open-use-tmm' is nil,
+	       display the menu bar of the root frame's selected window.  */
+	    display_menu_bar (XWINDOW (FRAME_SELECTED_WINDOW (rf)));
+	  else if (FRAME_MENU_BAR_LINES (f) > 0)
+	    display_menu_bar (w);
+	}
 
 #ifdef HAVE_WINDOW_SYSTEM
       if (FRAME_WINDOW_P (f))
@@ -27361,10 +27394,19 @@ display_tty_menu_item (const char *item_text, int width, int face_id,
 {
   struct it it;
   struct frame *f = SELECTED_FRAME ();
-  struct window *w = XWINDOW (f->selected_window);
   struct glyph_row *row;
   size_t item_len = strlen (item_text);
 
+  struct frame *rf = NULL;
+
+  if (FRAME_PARENT_FRAME (f) && !FRAME_WINDOW_P (f)
+      && FRAME_MENU_BAR_LINES (f) == 0
+      && FRAME_MENU_BAR_LINES (rf = root_frame (f)) != 0
+      && NILP (Fdefault_value (Qtty_menu_open_use_tmm)))
+    f = rf;
+
+  struct window *w = XWINDOW (f->selected_window);
+
   eassert (FRAME_TERMCAP_P (f));
 
   /* Don't write beyond the matrix's last row.  This can happen for
@@ -38480,6 +38522,7 @@ syms_of_xdisp (void)
   DEFSYM (Qnhdrag, "nhdrag");
   DEFSYM (Qvdrag, "vdrag");
   DEFSYM (Qhourglass, "hourglass");
+  DEFSYM (Qtty_menu_open_use_tmm, "tty-menu-open-use-tmm");
 }