GNU bug report logs - #78980
31.0.50; C-z crashes emacsclient -nw

Previous Next

Package: emacs;

Reported by: Eli Zaretskii <eliz <at> gnu.org>

Date: Wed, 9 Jul 2025 13:33:02 UTC

Severity: normal

Found in version 31.0.50

To reply to this bug, email your comments to 78980 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to rudalics <at> gmx.at, gerd.moellmann <at> gmail.com, pipcet <at> protonmail.com, bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 13:33:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Eli Zaretskii <eliz <at> gnu.org>:
New bug report received and forwarded. Copy sent to rudalics <at> gmx.at, gerd.moellmann <at> gmail.com, pipcet <at> protonmail.com, bug-gnu-emacs <at> gnu.org. (Wed, 09 Jul 2025 13:33:02 GMT) Full text and rfc822 format available.

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

From: Eli Zaretskii <eliz <at> gnu.org>
To: bug-gnu-emacs <at> gnu.org
Subject: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 09 Jul 2025 16:31:25 +0300
This bug report will be sent to the Bug-GNU-Emacs mailing list
and the GNU bug tracker at debbugs.gnu.org.  Please check that
the From: line contains a valid email address.  After a delay of up
to one day, you should receive an acknowledgment at that address.

Please write in English if possible, as the Emacs maintainers
usually do not have translators for other languages.

Please describe exactly what actions triggered the bug, and
the precise symptoms of the bug.  If you can, give a recipe
starting from 'emacs -Q':

To reproduce:

 $ emacs -Q -nw
 M-x server-start RET

Then from another terminal:

 $ emacsclient -nw
 C-z

This crashes Emacs.  Here's the backtrace:

  Thread 1 "emacs" hit Breakpoint 1, terminate_due_to_signal (sig=sig <at> entry=6, \
backtrace_limit=backtrace_limit <at> entry=2147483647) at emacs.c:442
  442     {
  (gdb) bt
  #0  terminate_due_to_signal
      (sig=sig <at> entry=6, backtrace_limit=backtrace_limit <at> entry=2147483647)
      at emacs.c:442
  #1  0x0000561edf8b3962 in die
      (msg=msg <at> entry=0x561edfbb609a "CONSP (a)", file=file <at> entry=0x561edfbb6020\
 "lisp.h", line=line <at> entry=1477) at alloc.c:7355
  #2  0x0000561edf89b9cf in XCONS (a=<optimized out>)
      at /home/eliz/git/emacs/trunk/src/lisp.h:1477
  #3  0x0000561edf89c48c in XCONS (a=<optimized out>) at dispnew.c:3364
  #4  XCAR (c=<optimized out>) at /home/eliz/git/emacs/trunk/src/lisp.h:1504
  #5  frames_in_reverse_z_order (f=<optimized out>, visible_only=true)
      at dispnew.c:3458
  #6  0x0000561edf8d47c3 in is_tty_root_frame_with_visible_child
      (f=<optimized out>) at dispnew.c:3518
  #7  0x0000561edf92e0a1 in redisplay_internal () at xdisp.c:17390
  #8  0x0000561edfa46b6a in read_char
      (commandflag=1, map=XIL(0x7f7257b0e3a3), prev_event=XIL(0), used_mouse_me\
nu=0x7fff32d5291b, end_time=0x0) at keyboard.c:2672
  #9  0x0000561edfa48bdc in read_key_sequence
      (keybuf=0x7fff32d52a70, prompt=XIL(0), dont_downcase_last=<optimized out>\
, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<opt\
imized out>, disable_text_conversion_p=false) at keyboard.c:10882
  #10 0x0000561edfa4a9a1 in command_loop_1 () at keyboard.c:1424
  #11 0x0000561edfad8247 in internal_condition_case
      (bfun=bfun <at> entry=0x561edfa4a730 <command_loop_1>, handlers=handlers <at> entry\
=XIL(0x90), hfun=hfun <at> entry=0x561edfa3ccf0 <cmd_error>) at eval.c:1684
  #12 0x0000561edfa3255e in command_loop_2 (handlers=handlers <at> entry=XIL(0x90))
      at keyboard.c:1163
  #13 0x0000561edfad80c9 in internal_catch
      (tag=tag <at> entry=XIL(0x125d0), func=func <at> entry=0x561edfa32530 <command_loop\
_2>, arg=arg <at> entry=XIL(0x90)) at eval.c:1364
  #14 0x0000561edfa324f9 in command_loop () at keyboard.c:1141
  #15 0x0000561edfa3c7a5 in recursive_edit_1 () at keyboard.c:749
  #16 0x0000561edfa3cb58 in Frecursive_edit () at keyboard.c:832
  #17 0x0000561edf8c80d2 in main (argc=<optimized out>, argv=<optimized out>)
      at emacs.c:2582

I guess 'frames' is nil here, so we hit the assertion violation?

  Lisp_Object
  frames_in_reverse_z_order (struct frame *f, bool visible_only)
  {
    struct frame *root = root_frame (f);
    Lisp_Object frames = frames_with_root (root, visible_only);
    frames = CALLN (Fsort, frames, QClessp, Qframe__z_order_lessp);
    eassert (FRAMEP (XCAR (frames)));
    eassert (XFRAME (XCAR (frames)) == root);
    return frames;
  }



If Emacs crashed, and you have the Emacs process in the gdb debugger,
please include the output from the following gdb commands:
    'bt full' and 'xbacktrace'.
For information about debugging Emacs, please read the file
/home/eliz/git/emacs/trunk/etc/DEBUG.

In GNU Emacs 31.0.50 (build 276, x86_64-pc-linux-gnu, GTK+ Version
 3.24.33, cairo version 1.16.0) of 2025-07-09 built on
 maintain0p.gnu.org
Repository revision: 8497cfeaeac832ff98730388567526a42b321d85
Repository branch: master
System Description: Trisquel GNU/Linux Aramo (11.0.1)

Configured using:
 'configure --with-gif=ifavailable --with-tiff=ifavailable
 --with-jpeg=ifavailable --with-xpm=ifavailable
 --without-native-compilation --enable-checking=yes,glyphs 'CFLAGS=-O2
 -g3''

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG
LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 M17N_FLT MODULES NOTIFY
INOTIFY PDUMPER PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF
TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINERAMA XINPUT2 XPM XRANDR GTK3
ZLIB

Important settings:
  value of $LC_ALL: en_US.UTF-8
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  minibuffer-regexp-mode: t
  line-number-mode: t
  indent-tabs-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug lisp-mnt message mailcap yank-media puny
dired dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg
rfc6068 epg-config gnus-util text-property-search mm-decode mm-bodies
mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail
rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils time-date
subr-x cl-loaddefs cl-lib term/xterm xterm byte-opt gv bytecomp
byte-compile rmc iso-transl tooltip cconv eldoc paren electric uniquify
ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/x-win x-win
term/common-win x-dnd touch-screen tool-bar dnd fontset image regexp-opt
fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode
register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select
scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors
frame minibuffer nadvice seq simple cl-generic indonesian philippine
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech
european ethiopic indian cyrillic chinese composite emoji-zwj charscript
charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure
cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp
files window text-properties overlay sha1 md5 base64 format env
code-pages mule custom widget keymap hashtable-print-readable backquote
threads dbusbind inotify lcms2 dynamic-setting system-font-setting
font-render-setting cairo gtk x-toolkit xinput2 x multi-tty move-toolbar
make-network-process tty-child-frames emacs)

Memory information:
((conses 16 48462 10465) (symbols 48 6200 0) (strings 32 14276 1689)
 (string-bytes 1 349218) (vectors 16 7538) (vector-slots 8 63531 7250)
 (floats 8 25 355) (intervals 56 245 8) (buffers 984 10))





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 14:14:01 GMT) Full text and rfc822 format available.

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

From: Pip Cet <pipcet <at> protonmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Gerd Möllmann <gerd.moellmann <at> gmail.com>,
 78980 <at> debbugs.gnu.org, martin rudalics <rudalics <at> gmx.at>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 09 Jul 2025 14:13:32 +0000
"Eli Zaretskii" <eliz <at> gnu.org> writes:

> To reproduce:
>
>  $ emacs -Q -nw
>  M-x server-start RET
>
> Then from another terminal:
>
>  $ emacsclient -nw
>  C-z
>
> This crashes Emacs.  Here's the backtrace:

Thanks for reporting this as a separate bug, and for taking the trouble
to confirm it!

I've been testing the possible fix for bug#78899 with this patch, but I
don't understand the structures or how they changed lately, so all it
does is accept that frames_with_root and frames_in_reverse_z_order can
return nil.

diff --git a/src/dispnew.c b/src/dispnew.c
index d65a7cbc1f1..025b1fbd99a 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3455,8 +3455,8 @@ frames_in_reverse_z_order (struct frame *f, bool visible_only)
   struct frame *root = root_frame (f);
   Lisp_Object frames = frames_with_root (root, visible_only);
   frames = CALLN (Fsort, frames, QClessp, Qframe__z_order_lessp);
-  eassert (FRAMEP (XCAR (frames)));
-  eassert (XFRAME (XCAR (frames)) == root);
+  eassert (NILP (frames) || FRAMEP (XCAR (frames)));
+  eassert (NILP (frames) || XFRAME (XCAR (frames)) == root);
   return frames;
 }
 
@@ -3516,7 +3516,7 @@ is_tty_root_frame_with_visible_child (struct frame *f)
   if (!is_tty_root_frame (f))
     return false;
   Lisp_Object z_order = frames_in_reverse_z_order (f, true);
-  return CONSP (XCDR (z_order));
+  return CONSP (z_order) && CONSP (XCDR (z_order));
 }
 
 /* Return the index of the first enabled row in MATRIX, or -1 if there

in frames_in_reverse_z_order, the root frame is not visible, but
visible_only is true, so frames_with_root returns Qnil correctly, I
think.

However, I don't think we should ever hit this code for invisible
frames; maybe frame_redisplay_p should return false for them?  That
would match its documentation:

/** Return true if F can be redisplayed, that is if F is visible and, if
    F is a tty frame, all its ancestors are visible too.  */

From a76506f131b2d47b0e1dc59ecd6c581e431d298c Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet <at> protonmail.com>
Subject: [PATCH] Fix crashes when "emacsclient -nw" frames are suspended
 (bug#78980)

* src/frame.c (frame_redisplay_p): Start loop with 'f', not its parent
frame.  Simplify return expression.
---
 src/frame.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/frame.c b/src/frame.c
index 70e200d9219..36ce36436f3 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -364,8 +364,8 @@ frame_redisplay_p (struct frame *f)
 {
   if (is_tty_frame (f))
     {
-      struct frame *p = FRAME_PARENT_FRAME (f);
-      struct frame *q = NULL;
+      struct frame *p = f;
+      struct frame *q = f;
 
       while (p)
 	{
@@ -387,7 +387,7 @@ frame_redisplay_p (struct frame *f)
 	 frame of its terminal.  Any other tty frame can be redisplayed
 	 iff it is the top frame of its terminal itself which must be
 	 always visible.  */
-      return (q ? q == r : f == r);
+      return q == r;
     }
   else
 #ifndef HAVE_X_WINDOWS
-- 
2.50.0






Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 14:41:02 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: Pip Cet <pipcet <at> protonmail.com>
Cc: 78980 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>,
 martin rudalics <rudalics <at> gmx.at>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 09 Jul 2025 16:40:11 +0200
Pip Cet <pipcet <at> protonmail.com> writes:

> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>
>> To reproduce:
>>
>>  $ emacs -Q -nw
>>  M-x server-start RET
>>
>> Then from another terminal:
>>
>>  $ emacsclient -nw
>>  C-z
>>
>> This crashes Emacs.  Here's the backtrace:
>
> Thanks for reporting this as a separate bug, and for taking the trouble
> to confirm it!
>
> I've been testing the possible fix for bug#78899 with this patch, but I
> don't understand the structures or how they changed lately, so all it
> does is accept that frames_with_root and frames_in_reverse_z_order can
> return nil.
>
> diff --git a/src/dispnew.c b/src/dispnew.c
> index d65a7cbc1f1..025b1fbd99a 100644
> --- a/src/dispnew.c
> +++ b/src/dispnew.c
> @@ -3455,8 +3455,8 @@ frames_in_reverse_z_order (struct frame *f, bool visible_only)
>    struct frame *root = root_frame (f);
>    Lisp_Object frames = frames_with_root (root, visible_only);
>    frames = CALLN (Fsort, frames, QClessp, Qframe__z_order_lessp);
> -  eassert (FRAMEP (XCAR (frames)));
> -  eassert (XFRAME (XCAR (frames)) == root);
> +  eassert (NILP (frames) || FRAMEP (XCAR (frames)));
> +  eassert (NILP (frames) || XFRAME (XCAR (frames)) == root);
>    return frames;
>  }
>  
> @@ -3516,7 +3516,7 @@ is_tty_root_frame_with_visible_child (struct frame *f)
>    if (!is_tty_root_frame (f))
>      return false;
>    Lisp_Object z_order = frames_in_reverse_z_order (f, true);
> -  return CONSP (XCDR (z_order));
> +  return CONSP (z_order) && CONSP (XCDR (z_order));
>  }
>  
>  /* Return the index of the first enabled row in MATRIX, or -1 if there
>
> in frames_in_reverse_z_order, the root frame is not visible, but
> visible_only is true, so frames_with_root returns Qnil correctly, I
> think.
>
> However, I don't think we should ever hit this code for invisible
> frames; maybe frame_redisplay_p should return false for them?  That
> would match its documentation:
>
> /** Return true if F can be redisplayed, that is if F is visible and, if
>     F is a tty frame, all its ancestors are visible too.  */
>
> From a76506f131b2d47b0e1dc59ecd6c581e431d298c Mon Sep 17 00:00:00 2001
> From: Pip Cet <pipcet <at> protonmail.com>
> Subject: [PATCH] Fix crashes when "emacsclient -nw" frames are suspended
>  (bug#78980)
>
> * src/frame.c (frame_redisplay_p): Start loop with 'f', not its parent
> frame.  Simplify return expression.
> ---
>  src/frame.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/src/frame.c b/src/frame.c
> index 70e200d9219..36ce36436f3 100644
> --- a/src/frame.c
> +++ b/src/frame.c
> @@ -364,8 +364,8 @@ frame_redisplay_p (struct frame *f)
>  {
>    if (is_tty_frame (f))
>      {
> -      struct frame *p = FRAME_PARENT_FRAME (f);
> -      struct frame *q = NULL;
> +      struct frame *p = f;
> +      struct frame *q = f;
>  
>        while (p)
>  	{
> @@ -387,7 +387,7 @@ frame_redisplay_p (struct frame *f)
>  	 frame of its terminal.  Any other tty frame can be redisplayed
>  	 iff it is the top frame of its terminal itself which must be
>  	 always visible.  */
> -      return (q ? q == r : f == r);
> +      return q == r;
>      }
>    else
>  #ifndef HAVE_X_WINDOWS

I haven't tested/run something, but from reading the code, I'd say the
story begins in suspend-tty, namely here

term.c<master>:
 2437       if (FRAMEP (t->display_info.tty->top_frame))
 2438         {
 2439           struct frame *top = XFRAME (t->display_info.tty->top_frame);
 2440           SET_FRAME_VISIBLE (root_frame (top), false);
 2441         }

This makes the root frame invisible, and frames_with_root, which is
called in the end, returns nil then when called with such a root and
visible_only == true. That's actually okay, I think.

I find more interesting what redisplay_internal does. The first thing
I see is

xdisp.c:
17387       /* If this is a window on a tty root frame displaying a child frame,
17388          the current matrix of W may contain glyphs of that child frame.
17389          Don't try shortcuts that might use the current matrix in this case.  */
17390       && !is_tty_root_frame_with_visible_child (XFRAME (w->frame)))

Here w->frame can be invisible, apparently. And I wonder if one should
check if the root frame of w->frame is visible as a starter. Something
like `FRAME_VISIBLE_P (root_frame (XFRAME (w->frame)))` before checking
`is_tty_root...`. Because I wonder if that wouldn't be more correct also
in the GUI case.

And there are potentially more places. I don't see at the moment if
that's already done somewhere in redisplay_internal, but maybe we should
discard redisplays for invisible frames somewhere further down, too. Or
one could first add assert that frames are visible when we display them,
e.g. in redisplay_window and so on? 




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 15:09:04 GMT) Full text and rfc822 format available.

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

From: martin rudalics <rudalics <at> gmx.at>
To: Pip Cet <pipcet <at> protonmail.com>, Eli Zaretskii <eliz <at> gnu.org>
Cc: Gerd Möllmann <gerd.moellmann <at> gmail.com>,
 78980 <at> debbugs.gnu.org
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 9 Jul 2025 17:07:40 +0200
> * src/frame.c (frame_redisplay_p): Start loop with 'f', not its parent
> frame.  Simplify return expression.

This one is a clear bug fix.  Please install it.

Thanks, martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 15:10:06 GMT) Full text and rfc822 format available.

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

From: martin rudalics <rudalics <at> gmx.at>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>,
 Pip Cet <pipcet <at> protonmail.com>
Cc: 78980 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 9 Jul 2025 17:09:41 +0200
> I find more interesting what redisplay_internal does. The first thing
> I see is
>
> xdisp.c:
> 17387       /* If this is a window on a tty root frame displaying a child frame,
> 17388          the current matrix of W may contain glyphs of that child frame.
> 17389          Don't try shortcuts that might use the current matrix in this case.  */
> 17390       && !is_tty_root_frame_with_visible_child (XFRAME (w->frame)))
>
> Here w->frame can be invisible, apparently. And I wonder if one should
> check if the root frame of w->frame is visible as a starter. Something
> like `FRAME_VISIBLE_P (root_frame (XFRAME (w->frame)))` before checking
> `is_tty_root...`. Because I wonder if that wouldn't be more correct also
> in the GUI case.
>
> And there are potentially more places. I don't see at the moment if
> that's already done somewhere in redisplay_internal, but maybe we should
> discard redisplays for invisible frames somewhere further down, too. Or
> one could first add assert that frames are visible when we display them,
> e.g. in redisplay_window and so on?

There is one loose end for GUIs: When I have a child frame marked as
visible, its parent frame is marked as invisible and their root frame is
marked as visible, then I have no idea whether there exists a window
manager that expects us to redraw the child frame marked as visible.  At
least when that child frame corresponds to a modal window.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Wed, 09 Jul 2025 16:58:05 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: martin rudalics <rudalics <at> gmx.at>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Wed, 09 Jul 2025 18:57:45 +0200
martin rudalics <rudalics <at> gmx.at> writes:

>> I find more interesting what redisplay_internal does. The first thing
>> I see is
>>
>> xdisp.c:
>> 17387       /* If this is a window on a tty root frame displaying a child frame,
>> 17388          the current matrix of W may contain glyphs of that child frame.
>> 17389          Don't try shortcuts that might use the current matrix in this case.  */
>> 17390       && !is_tty_root_frame_with_visible_child (XFRAME (w->frame)))
>>
>> Here w->frame can be invisible, apparently. And I wonder if one should
>> check if the root frame of w->frame is visible as a starter. Something
>> like `FRAME_VISIBLE_P (root_frame (XFRAME (w->frame)))` before checking
>> `is_tty_root...`. Because I wonder if that wouldn't be more correct also
>> in the GUI case.
>>
>> And there are potentially more places. I don't see at the moment if
>> that's already done somewhere in redisplay_internal, but maybe we should
>> discard redisplays for invisible frames somewhere further down, too. Or
>> one could first add assert that frames are visible when we display them,
>> e.g. in redisplay_window and so on?
>
> There is one loose end for GUIs: When I have a child frame marked as
> visible, its parent frame is marked as invisible and their root frame is
> marked as visible, then I have no idea whether there exists a window
> manager that expects us to redraw the child frame marked as visible.  At
> least when that child frame corresponds to a modal window.
>
> martin

Maybe one could pack all that in a new function, say
is_display_optimizable that one would use instead of
is_tty_root_frame_with_visible_children? For tty frames It could check
that the frame is not an invisible root, and then check for visible
chldren.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Thu, 10 Jul 2025 08:47:01 GMT) Full text and rfc822 format available.

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

From: martin rudalics <rudalics <at> gmx.at>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Thu, 10 Jul 2025 10:45:53 +0200
> Maybe one could pack all that in a new function, say
> is_display_optimizable that one would use instead of
> is_tty_root_frame_with_visible_children? For tty frames It could check
> that the frame is not an invisible root, and then check for visible
> chldren.

When I originally wrote the code for GUIs (on X and WINDOWS) I simply
relied on the promise made by the system designers that the window
manager will handle child frames as advertised.  Evaluate the following
forms in a row:

(setq frame1 (selected-frame))
(setq frame2 (make-frame `((parent-frame . ,frame1) (top . 40) (left . 40)
			   (width . 40) (height . 30))))
(setq frame3 (make-frame `((parent-frame . ,frame2) (top . 40) (left . 40)
			   (width . 20) (height . 15))))
(make-frame-invisible frame2)

On each GUI I know of, the last form will make frame3 invisible without
Emacs contributing anything to it.   Making frame2 visible again will
also make frame3 visible.  Making frame3 invisible before making frame2
invisible and making frame2 visible again will leave frame3 invisible.

According to what I read, an exception should be made for modal frames.
Hence if frame3 were a modal frame, it could be visible even if frame2
(or frame1) aren't.  But we do not have an interface for making our own
modal frames so I cannot check this.  Here any modal GUI windows are
likely child windows of the root and behave like popup menus - as long
as they are visible you cannot access any other window.

In either case, this means that the window manager and/or the toolkit
have to keep internally their own copy of the Emacs frame tree and
handle visibility autonomously.  On a TTY we have to (or probably
should) emulate that behavior ourselves.

martin




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Thu, 10 Jul 2025 09:36:04 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: martin rudalics <rudalics <at> gmx.at>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Thu, 10 Jul 2025 11:35:41 +0200
martin rudalics <rudalics <at> gmx.at> writes:

>> Maybe one could pack all that in a new function, say
>> is_display_optimizable that one would use instead of
>> is_tty_root_frame_with_visible_children? For tty frames It could check
>> that the frame is not an invisible root, and then check for visible
>> chldren.
>
> When I originally wrote the code for GUIs (on X and WINDOWS) I simply
> relied on the promise made by the system designers that the window
> manager will handle child frames as advertised.  Evaluate the following
> forms in a row:
>
> (setq frame1 (selected-frame))
> (setq frame2 (make-frame `((parent-frame . ,frame1) (top . 40) (left . 40)
> 			   (width . 40) (height . 30))))
> (setq frame3 (make-frame `((parent-frame . ,frame2) (top . 40) (left . 40)
> 			   (width . 20) (height . 15))))
> (make-frame-invisible frame2)
>
> On each GUI I know of, the last form will make frame3 invisible without
> Emacs contributing anything to it.   Making frame2 visible again will
> also make frame3 visible.  Making frame3 invisible before making frame2
> invisible and making frame2 visible again will leave frame3 invisible.
>
> According to what I read, an exception should be made for modal frames.
> Hence if frame3 were a modal frame, it could be visible even if frame2
> (or frame1) aren't.  But we do not have an interface for making our own
> modal frames so I cannot check this.  Here any modal GUI windows are
> likely child windows of the root and behave like popup menus - as long
> as they are visible you cannot access any other window.
>
> In either case, this means that the window manager and/or the toolkit
> have to keep internally their own copy of the Emacs frame tree and
> handle visibility autonomously.  On a TTY we have to (or probably
> should) emulate that behavior ourselves.

I think one thing you are saying is that we should leave any checks for
visibility of GUI frames, as far as redisplay is concerned, as-is,
right? That is basically don't check.

That leaves the decision where to implement the "WM" functionality in
the tty case, and what that functionality should be.

Form my POV, redisplay_internal is the place where to put that because
that's the only "central place" in redisplay.

The functionality on GUIs sounds like we should have something like
  
  bool is_displayed(struct frame *f) {
      // Öeave window system frames alone
      if (!is_tty_frame(f))
          return true;
      // Don't display if not marked visible.
      if (!FRAME_VISIBLE_P(f))
          return false;
      // If marked visible but parent isn't displayed
      const struct frame *oarent = FRAME_PARENT_FRAME(f);
      return parent ? is_displayed(parent) : true;
  }

WDYT?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Thu, 10 Jul 2025 14:57:02 GMT) Full text and rfc822 format available.

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

From: martin rudalics <rudalics <at> gmx.at>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Thu, 10 Jul 2025 16:55:53 +0200
> The functionality on GUIs sounds like we should have something like
>
>    bool is_displayed(struct frame *f) {
>        // Öeave window system frames alone
>        if (!is_tty_frame(f))
>            return true;
>        // Don't display if not marked visible.
>        if (!FRAME_VISIBLE_P(f))
>            return false;
>        // If marked visible but parent isn't displayed
>        const struct frame *oarent = FRAME_PARENT_FRAME(f);
>        return parent ? is_displayed(parent) : true;
>    }
>
> WDYT?

But that's precisely what frame_redisplay_p is supposed to accomplish.
Look at the patch below which further simplifies what Pip Cet proposed
earlier.

martin


diff --git a/src/frame.c b/src/frame.c
index 70e200d9219..2d88ad94114 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -358,36 +358,27 @@ DEFUN ("window-system", Fwindow_system, Swindow_system, 0, 1, 0,
 }

 /** Return true if F can be redisplayed, that is if F is visible and, if
-    F is a tty frame, all its ancestors are visible too.  */
+    F is a tty frame, all its ancestors are visible too and F's root
+    frame is its terminal's top frame..  */
 bool
 frame_redisplay_p (struct frame *f)
 {
   if (is_tty_frame (f))
     {
-      struct frame *p = FRAME_PARENT_FRAME (f);
-      struct frame *q = NULL;
+      struct tty_display_info *tty = FRAME_TTY (f);
+      struct frame *r = XFRAME (tty->top_frame);

-      while (p)
+      while (f)
 	{
-	  if (!p->visible)
+	  if (!f->visible)
 	    /* A tty child frame cannot be redisplayed if one of its
 	       ancestors is invisible.  */
 	    return false;
 	  else
-	    {
-	      q = p;
-	      p = FRAME_PARENT_FRAME (p);
-	    }
+	    f = FRAME_PARENT_FRAME (f);
 	}

-      struct tty_display_info *tty = FRAME_TTY (f);
-      struct frame *r = XFRAME (tty->top_frame);
-
-      /* A tty child frame can be redisplayed iff its root is the top
-	 frame of its terminal.  Any other tty frame can be redisplayed
-	 iff it is the top frame of its terminal itself which must be
-	 always visible.  */
-      return (q ? q == r : f == r);
+      return f == r;
     }
   else
 #ifndef HAVE_X_WINDOWS

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Thu, 10 Jul 2025 15:09:02 GMT) Full text and rfc822 format available.

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

From: Gerd Möllmann <gerd.moellmann <at> gmail.com>
To: martin rudalics <rudalics <at> gmx.at>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Thu, 10 Jul 2025 17:08:37 +0200
martin rudalics <rudalics <at> gmx.at> writes:

>  > The functionality on GUIs sounds like we should have something like
>  >
>  >    bool is_displayed(struct frame *f) {
>  >        // Öeave window system frames alone
>  >        if (!is_tty_frame(f))
>  >            return true;
>  >        // Don't display if not marked visible.
>  >        if (!FRAME_VISIBLE_P(f))
>  >            return false;
>  >        // If marked visible but parent isn't displayed
>  >        const struct frame *oarent = FRAME_PARENT_FRAME(f);
>  >        return parent ? is_displayed(parent) : true;
>  >    }
>  >
>  > WDYT?
>
> But that's precisely what frame_redisplay_p is supposed to accomplish.
> Look at the patch below which further simplifies what Pip Cet proposed
> earlier.

Than I guess I've simply not understood what's going on. Or maybe the
problem is that a call to frame_redisplay_p is missing in
redisplay_interlal, where is_tty_root_frame_with_visible_child is
called? Anyway, I'll better shut up :-).




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#78980; Package emacs. (Thu, 10 Jul 2025 16:21:02 GMT) Full text and rfc822 format available.

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

From: martin rudalics <rudalics <at> gmx.at>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: 78980 <at> debbugs.gnu.org, Pip Cet <pipcet <at> protonmail.com>,
 Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#78980: 31.0.50; C-z crashes emacsclient -nw
Date: Thu, 10 Jul 2025 18:19:53 +0200
> Than I guess I've simply not understood what's going on. Or maybe the
> problem is that a call to frame_redisplay_p is missing in
> redisplay_interlal, where is_tty_root_frame_with_visible_child is
> called?

No.  It was a simple bug in frame_redisplay_p which disregarded the
visibility of the argument frame on ttys.  Normally, the tty top frame
is always visible - it isn't after 'suspend-tty' does

	  SET_FRAME_VISIBLE (root_frame (top), false);

BTW my last patch was wrong again, the below one should work.

martin

	
diff --git a/src/frame.c b/src/frame.c
index 70e200d9219..714a786a29b 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -358,36 +358,29 @@ DEFUN ("window-system", Fwindow_system, Swindow_system, 0, 1, 0,
 }

 /** Return true if F can be redisplayed, that is if F is visible and, if
-    F is a tty frame, all its ancestors are visible too.  */
+    F is a tty frame, all its ancestors are visible too and F's root
+    frame is its terminal's top frame..  */
 bool
 frame_redisplay_p (struct frame *f)
 {
   if (is_tty_frame (f))
     {
-      struct frame *p = FRAME_PARENT_FRAME (f);
-      struct frame *q = NULL;
+      struct tty_display_info *tty = FRAME_TTY (f);
+      struct frame *r = XFRAME (tty->top_frame);

-      while (p)
+      while (f)
 	{
-	  if (!p->visible)
+	  if (!f->visible)
 	    /* A tty child frame cannot be redisplayed if one of its
 	       ancestors is invisible.  */
 	    return false;
+	  else if (f == r)
+	    return true;
 	  else
-	    {
-	      q = p;
-	      p = FRAME_PARENT_FRAME (p);
-	    }
+	    f = FRAME_PARENT_FRAME (f);
 	}

-      struct tty_display_info *tty = FRAME_TTY (f);
-      struct frame *r = XFRAME (tty->top_frame);
-
-      /* A tty child frame can be redisplayed iff its root is the top
-	 frame of its terminal.  Any other tty frame can be redisplayed
-	 iff it is the top frame of its terminal itself which must be
-	 always visible.  */
-      return (q ? q == r : f == r);
+      return false;
     }
   else
 #ifndef HAVE_X_WINDOWS




This bug report was last modified 1 day ago.

Previous Next


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