GNU bug report logs - #78899
30.1; garbage inserted in the terminal buffer when quitting Emacs

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: Vincent Lefevre <vincent@HIDDEN>; dated Thu, 26 Jun 2025 00:39:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 9 Aug 2025 12:04:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Aug 09 08:04:39 2025
Received: from localhost ([127.0.0.1]:40537 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1ukiJR-0006up-J4
	for submit <at> debbugs.gnu.org; Sat, 09 Aug 2025 08:04:39 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:37862)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1ukiJN-0006uY-MB
 for 78899 <at> debbugs.gnu.org; Sat, 09 Aug 2025 08:04:35 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1ukiJG-0000tf-RC; Sat, 09 Aug 2025 08:04:26 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=MqSEJxT1qghTxP0Ax0QPRbfGeKWDqPOt7sOAoruTrSo=; b=Ov9WpkaBloIM
 /1yj2DTD8lxQNoSR9ZqEgi9UC02AqMsFcX/l6z/r9Bi9g1Ze2aVuMRNU0x1GAYOKPzozbQ9/e7Mh6
 KOq5QnsUwEwYBPc+tF4LF+HADMiScbyEHjNnTdssTkZn7aaCC5C6kLLqvnaUA9qisMCCVFeAi9/2c
 W1uZs6d24lTW8+z3KRXOhJyF0bVh3N785erjGK9yj+nTz5Gb7ixqmZNeyca31ynqKUb+EujPF/1cZ
 TFfWwdX46DRd0V87JPxfzp+atgynCV38rDF3FarLGaqLnoZ+Xqzp6enbcyvmacshZju4fPJjWj49r
 MLYUrVUBD0owQSXwpx55xA==;
Date: Sat, 09 Aug 2025 15:04:11 +0300
Message-Id: <864iugn1l0.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: pipcet@HIDDEN
In-Reply-To: <86a54r2wok.fsf@HIDDEN> (message from Eli Zaretskii on Sat, 26
 Jul 2025 11:17:15 +0300)
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN> <86h5zw2klj.fsf@HIDDEN>
 <bc2ac5f04c0214ab53a0bd0f0f5e46b4@HIDDEN> <87qzypsibk.fsf@HIDDEN>
 <86a54r2wok.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, jared@HIDDEN, 78899 <at> debbugs.gnu.org,
 vincent@HIDDEN, monnier@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ping! Ping! Can we please make some progress here?

> Cc: luangruo@HIDDEN, vincent@HIDDEN, 78899 <at> debbugs.gnu.org,
>  jared@HIDDEN, monnier@HIDDEN
> Date: Sat, 26 Jul 2025 11:17:15 +0300
> From: Eli Zaretskii <eliz@HIDDEN>
> 
> Ping!  Any further progress with this?
> 
> > Date: Wed, 09 Jul 2025 11:40:53 +0000
> > From: Pip Cet <pipcet@HIDDEN>
> > Cc: Eli Zaretskii <eliz@HIDDEN>, Stefan Monnier <monnier@HIDDEN>, vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> > 
> > "Jared Finder" <jared@HIDDEN> writes:
> > 
> > > On 2025-07-01 04:53, Eli Zaretskii wrote:
> > >>> Date: Mon, 30 Jun 2025 22:47:45 +0000
> > >>> From: Pip Cet <pipcet@HIDDEN>
> > >>> Cc: vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> > >>
> > >> Thanks.  Jared and Stefan, any comments?
> > >
> > > Does the most recent proposed patch work when Emacs is used across
> > > multiple terminals?
> > 
> > Probably not, no.  It doesn't even work for suspending a terminal.
> > Working on something better, based on your suggestion below.
> > 
> > I'm not sure whether I'm doing it right, but if I create a second
> > terminal with emacsclient -nw and suspend it with C-z, Emacs crashes.
> > I've worked around that for now, but if it's not just a local problem,
> > we should probably fix it.
> > 
> > (I also had xterm crash once while working on the selection code.
> > Unfortunately, all I have is the single-line segfault report in dmesg,
> > which isn't very helpful.)
> > 
> > > I expect it does not because kill-emacs-hook is
> > > only run when Emacs is fully killed.  I think it'd be more appropriate
> > > to add additional functionality to the terminal parameter
> > > tty-reset-strings to ensure the message is processed.
> > 
> > I agree that it would be nice to push a function to the
> > tty-mode-reset-strings terminal parameter, and run it from C if we can
> > (we can't run Lisp from within an Emergency Escape).
> > 
> > This requires reordering two calls: suspend-tty-functions does the
> > actual suspending in "emacsclient -nw" instances, so it can only be run
> > after we reset the tty modes, and shut_down_emacs should not inhibit
> > Lisp until after it has reset the sys modes .  There don't appear to be
> > any other users that expect the order to be different.
> > 
> > > But there's a scary message there about these escape strings and the
> > > emergency escape that I do not understand the ramifications of.
> > 
> > I think I understand what's being said there: we definitely need an
> > additional flag to prevent any potentially dangerous activity such as
> > running Lisp, or even inspecting Lisp data that might have mark bits
> > that we might fail to account for.
> > 
> > I resurrected inhibit_lisp_code for this purpose.
> > 
> > I'm still seeing other problems on slow xterms: xterm--query's
> > synchronous branch fails to work if other input arrives after the
> > (discard-input) but before the response to our query, which means that
> > if you start typing before the initial xterm--query calls complete,
> > you'll get the background description as input.
> > 
> > Since the delay of running multiple synchronous queries is also
> > significant, I think it would be best to switch to asynchronous
> > xterm--query in all but two cases: the new synchronization method needs
> > to be synchronous to ensure proper ordering, and the
> > gui-backend-get-selection method needs to be synchronous because the API
> > is.
> > 
> > There are also some minor improvements:
> > 
> > * turn-off-xterm-mouse-tracking-on-terminal now removes the sequences
> > successfully.
> > * xterm--query now uninstalls the input-decode-map binding when the
> > timeout expires.
> > 
> > Here's a snapshot (including the workaround to make frame suspension
> > works).
> > 
> > diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
> > index 4f23a909b69..9618e44ea30 100644
> > --- a/lisp/term/xterm.el
> > +++ b/lisp/term/xterm.el
> > @@ -743,9 +743,10 @@ xterm-standard-colors
> >  
> >  (defun xterm--report-background-handler ()
> >    ;; The reply should be: \e ] 11 ; rgb: NUMBER1 / NUMBER2 / NUMBER3 \e \\
> > -  (let ((str (xterm--read-string ?\e ?\\)))
> > -    (when (string-match
> > -           "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str)
> > +  (let ((str (xterm--read-string "\e\\")))
> > +    (when (and str
> > +               (string-match
> > +                "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str))
> >        (let ((recompute-faces
> >               (xterm-maybe-set-dark-background-mode
> >                (string-to-number (match-string 1 str) 16)
> > @@ -763,14 +764,10 @@ xterm--report-background-handler
> >  
> >  (defun xterm--version-handler ()
> >    ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
> > -  ;; If the timeout is completely removed for read-event, this
> > -  ;; might hang for terminals that pretend to be xterm, but don't
> > -  ;; respond to this escape sequence.  RMS' opinion was to remove
> > -  ;; it completely.  That might be right, but let's first try to
> > -  ;; see if by using a longer timeout we get rid of most issues.
> > -  (let ((str (xterm--read-string ?c)))
> > +  (let ((str (xterm--read-string "c")))
> >      ;; Since xterm-280, the terminal type (NUMBER1) is now 41 instead of 0.
> > -    (when (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str)
> > +    (when (and str
> > +               (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str))
> >        (let ((version (string-to-number (match-string 2 str))))
> >          (when (and (> version 2000)
> >                     (or (equal (match-string 1 str) "1")
> > @@ -816,6 +813,22 @@ xterm--version-handler
> >            ;;(xterm--init-activate-get-selection)
> >            (xterm--init-activate-set-selection))))))
> >  
> > +(defun xterm--name-and-version-handler ()
> > +  ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
> > +  ;; If the timeout is completely removed for read-event, this
> > +  ;; might hang for terminals that pretend to be xterm, but don't
> > +  ;; respond to this escape sequence.  RMS' opinion was to remove
> > +  ;; it completely.  That might be right, but let's first try to
> > +  ;; see if by using a longer timeout we get rid of most issues.
> > +  (let ((str (xterm--read-string "\e\\")))
> > +    (and str
> > +         (not xterm-mouse-mode-called)
> > +         ;; Only automatically enable xterm mouse on terminals
> > +         ;; confirmed to still support all critical editing
> > +         ;; workflows (bug#74833).
> > +         (string-match-p xterm--auto-xt-mouse-allowed-names str)
> > +         (xterm-mouse-mode 1))))
> > +
> >  (defvar xterm-query-timeout 2
> >    "Seconds to wait for an answer from the terminal.
> >  Can be nil to mean \"no timeout\".")
> > @@ -823,100 +836,42 @@ xterm-query-timeout
> >  (defvar xterm-query-redisplay-timeout 0.2
> >    "Seconds to wait before allowing redisplay during terminal query." )
> >  
> > -(defun xterm--read-event-for-query ()
> > +(defun xterm--read-event-for-query (end-time)
> >    "Like `read-event', but inhibit redisplay.
> >  
> >  By not redisplaying right away for xterm queries, we can avoid
> >  unsightly flashing during initialization.  Give up and redisplay
> >  anyway if we've been waiting a little while."
> > -  (let ((start-time (current-time)))
> > +  (let* ((timeout (float-time (time-subtract end-time (current-time))))
> > +         (first-timeout (min xterm-query-redisplay-timeout timeout))
> > +         (second-timeout (- timeout first-timeout)))
> >      (or (let ((inhibit-redisplay t))
> > -          (read-event nil nil xterm-query-redisplay-timeout))
> > -        (read-event nil nil
> > -                    (and xterm-query-timeout
> > -			 (max 0 (float-time
> > -				 (time-subtract
> > -				  xterm-query-timeout
> > -				  (time-since start-time)))))))))
> > -
> > -(defun xterm--read-string (term1 &optional term2)
> > -  "Read a string with terminating characters.
> > -This uses `xterm--read-event-for-query' internally."
> > -  (let ((str "")
> > -        chr last)
> > -    (while (and (setq last chr
> > -                      chr (xterm--read-event-for-query))
> > -                (if term2
> > -                    (not (and (equal last term1) (equal chr term2)))
> > -                  (not (equal chr term1))))
> > -      (setq str (concat str (string chr))))
> > -    (if term2
> > -        (substring str 0 -1)
> > -      str)))
> > -
> > -(defun xterm--query (query handlers &optional no-async)
> > +          (read-event nil nil (max 0 first-timeout)))
> > +        (read-event nil nil (max 0 second-timeout)))))
> > +
> > +(defun xterm--query (query handlers)
> >    "Send QUERY string to the terminal and watch for a response.
> >  HANDLERS is an alist with elements of the form (STRING . FUNCTION).
> >  We run the first FUNCTION whose STRING matches the input events."
> > -  ;; We used to query synchronously, but the need to use `discard-input' is
> > -  ;; rather annoying (bug#6758).  Maybe we could always use the asynchronous
> > -  ;; approach, but it's less tested.
> > -  ;; FIXME: Merge the two branches.
> > -  (let ((register
> > -         (lambda (handlers)
> > -           (dolist (handler handlers)
> > -             (define-key input-decode-map (car handler)
> > -               (lambda (&optional _prompt)
> > -                 ;; Unregister the handler, since we don't expect
> > -                 ;; further answers.
> > -                 (dolist (handler handlers)
> > -                   (define-key input-decode-map (car handler) nil))
> > -                 (funcall (cdr handler))
> > -                 []))))))
> > -    (if (and (or (null xterm-query-timeout) (input-pending-p))
> > -             (not no-async))
> > -        (progn
> > -          (funcall register handlers)
> > -          (send-string-to-terminal query))
> > -      ;; Pending input can be mistakenly returned by the calls to
> > -      ;; read-event below: discard it.
> > -      (discard-input)
> > -      (send-string-to-terminal query)
> > -      (while handlers
> > -        (let ((handler (pop handlers))
> > -              (i 0))
> > -          (while (and (< i (length (car handler)))
> > -                      (let ((evt (xterm--read-event-for-query)))
> > -                        (if (and (null evt) (= i 0) (not no-async))
> > -                            ;; Timeout on the first event: fallback on async.
> > -                            (progn
> > -                              (funcall register (cons handler handlers))
> > -                              (setq handlers nil)
> > -                              nil)
> > -                          (or (eq evt (aref (car handler) i))
> > -                              (progn (if evt (push evt unread-command-events))
> > -                                     nil)))))
> > -            (setq i (1+ i)))
> > -          (if (= i (length (car handler)))
> > -              (progn (setq handlers nil)
> > -                     (funcall (cdr handler)))
> > -            (while (> i 0)
> > -              (push (aref (car handler) (setq i (1- i)))
> > -                    unread-command-events))))))))
> > -
> > -(defun xterm--query-name-and-version ()
> > -  "Get the terminal name and version string (XTVERSION)."
> > -  ;; Reduce query timeout time. The default value causes a noticeable
> > -  ;; startup delay on terminals that ignore the query.
> > -  (let ((xterm-query-timeout 0.1))
> > -    (catch 'result
> > -      (xterm--query
> > -       "\e[>0q"
> > -       `(("\eP>|" . ,(lambda ()
> > -                       ;; The reply should be: \e P > | STRING \e \\
> > -                       (let ((str (xterm--read-string ?\e ?\\)))
> > -                         (throw 'result str))))))
> > -      nil)))
> > +  (let (unregister-functions)
> > +    (dolist (handler handlers)
> > +      (let* ((binding
> > +              (lambda (&optional _prompt)
> > +                ;; Unregister the handlers, since we don't expect
> > +                ;; further answers.
> > +                (mapc #'funcall unregister-functions)
> > +                (funcall (cdr handler))
> > +                []))
> > +             (unregister
> > +              (lambda ()
> > +                (when (eq (lookup-key input-decode-map (car handler))
> > +                          binding)
> > +                  (define-key input-decode-map (car handler) nil)))))
> > +        (define-key input-decode-map (car handler) binding)
> > +        (push unregister unregister-functions)))
> > +    (send-string-to-terminal query)
> > +    (run-with-timer xterm-query-timeout nil
> > +                    (lambda () (mapc #'funcall unregister-functions)))))
> >  
> >  (defun xterm--push-map (map basemap)
> >    ;; Use inheritance to let the main keymaps override those defaults.
> > @@ -965,16 +920,9 @@ xterm--init
> >  
> >    (when xterm-set-window-title
> >      (xterm--init-frame-title))
> > -  (when (and (not xterm-mouse-mode-called)
> > -             ;; Only automatically enable xterm mouse on terminals
> > -             ;; confirmed to still support all critical editing
> > -             ;; workflows (bug#74833).
> > -             (or (string-match-p xterm--auto-xt-mouse-allowed-types
> > -                                 (tty-type (selected-frame)))
> > -                 (and-let* ((name-and-version (xterm--query-name-and-version)))
> > -                   (string-match-p xterm--auto-xt-mouse-allowed-names
> > -                                   name-and-version))))
> > -    (xterm-mouse-mode 1))
> > +  (when (not xterm-mouse-mode-called)
> > +    (xterm--query "\e[>0q"
> > +                  '(("\eP>|" . xterm--name-and-version-handler))))
> >    ;; Unconditionally enable bracketed paste mode: terminals that don't
> >    ;; support it just ignore the sequence.
> >    (xterm--init-bracketed-paste-mode)
> > @@ -1053,6 +1001,33 @@ xterm--selection-char
> >      ('CLIPBOARD "c")
> >      (_ (error "Invalid selection type: %S" type))))
> >  
> > +(defun xterm--read-string (sequence &optional unread-all-events)
> > +  "Read input until we see SEQUENCE.  Return string of the input characters
> > +before its appearance, or nil if we hit a timeout.  Non-characters are
> > +stored in unread-command-events.  If UNREAD-ALL-EVENTS is non-nil, all
> > +events are stored there."
> > +  (setq sequence (nreverse (append sequence nil)))
> > +  (let ((end-time (time-add (current-time) xterm-query-timeout))
> > +        (n (length sequence))
> > +        events chars ret)
> > +    (unwind-protect
> > +        (catch 'failure
> > +          (while (not (equal (take n chars) sequence))
> > +            (let ((event (xterm--read-event-for-query end-time)))
> > +              (if event
> > +                  (push event events)
> > +                (throw 'failure nil))
> > +              (when (characterp event)
> > +                (push event chars))))
> > +          (setq ret (concat (nreverse (nthcdr n chars)))))
> > +      (dolist (event events)
> > +        (cond ((eq event (car sequence))
> > +               (pop sequence))
> > +              ((or (not (characterp event))
> > +                   (not (stringp ret))
> > +                   unread-all-events)
> > +               (push event unread-command-events)))))))
> > +
> >  (cl-defmethod gui-backend-get-selection
> >      (type data-type
> >       &context (window-system nil)
> > @@ -1064,27 +1039,16 @@ gui-backend-get-selection
> >                 (eql nil)))
> >    (unless (eq data-type 'STRING)
> >      (error "Unsupported data type %S" data-type))
> > -  (let ((query (concat "\e]52;" (xterm--selection-char type) ";")))
> > -    (with-temp-buffer
> > +  (with-temp-buffer
> > +    (let* ((query (concat "\e]52;" (xterm--selection-char type) ";")))
> >        (set-buffer-multibyte nil)
> > -      (xterm--query
> > -       ;; Use ST as query terminator to get ST as reply terminator (bug#36879).
> > -       (concat query "?\e\\")
> > -       (list (cons query
> > -                   (lambda ()
> > -                     ;; Read data up to the string terminator, ST.
> > -                     (let (char last)
> > -                       (while (and (setq char (read-char
> > -                                               nil nil
> > -                                               xterm-query-timeout))
> > -                                   (not (and (eq char ?\\)
> > -                                             (eq last ?\e))))
> > -                         (when last
> > -                           (insert last))
> > -                         (setq last char))))))
> > -       'no-async)
> > -      (base64-decode-region (point-min) (point-max))
> > -      (decode-coding-region (point-min) (point-max) 'utf-8-unix t))))
> > +      (send-string-to-terminal (concat query "?\e\\"))
> > +      (xterm--read-string query t)
> > +      (let ((str (xterm--read-string "\e\\")))
> > +        (when str
> > +          (insert str)
> > +          (base64-decode-region (point-min) (point-max))
> > +          (decode-coding-region (point-min) (point-max) 'utf-8-unix t))))))
> >  
> >  (cl-defmethod gui-backend-set-selection
> >      (type data
> > diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
> > index 89f9bbab608..4a4cb3a37b3 100644
> > --- a/lisp/xt-mouse.el
> > +++ b/lisp/xt-mouse.el
> > @@ -387,6 +387,9 @@ xterm-mouse-mode-called
> >    "If `xterm-mouse-mode' has been called already.
> >  This can be used to detect if xterm-mouse-mode was explicitly set.")
> >  
> > +(defvar xterm-mouse--terminals (make-hash-table :test 'eq :weakness 'key)
> > +  "Hash table of cleanups to be performed when xterm-mouse-mode is disabled.")
> > +
> >  ;;;###autoload
> >  (define-minor-mode xterm-mouse-mode
> >    "Toggle XTerm mouse mode.
> > @@ -507,6 +510,7 @@ xterm-mouse--tracking-sequence
> >  
> >  (defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal)
> >    "Enable xterm mouse tracking on TERMINAL."
> > +  (setq terminal (or terminal (frame-terminal)))
> >    (when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
> >  	     ;; Avoid the initial terminal which is not a termcap device.
> >  	     ;; FIXME: is there more elegant way to detect the initial
> > @@ -519,19 +523,35 @@ turn-on-xterm-mouse-tracking-on-terminal
> >          (define-key input-decode-map "\e[M" 'xterm-mouse-translate)
> >          (define-key input-decode-map "\e[<" 'xterm-mouse-translate-extended))
> >        (let ((enable (xterm-mouse-tracking-enable-sequence))
> > -            (disable (xterm-mouse-tracking-disable-sequence)))
> > +            (disable (xterm-mouse-tracking-disable-sequence))
> > +            (sync (lambda () (xterm-mouse--sync terminal))))
> >          (condition-case err
> >              (send-string-to-terminal enable terminal)
> >            ;; FIXME: This should use a dedicated error signal.
> >            (error (if (equal (cadr err) "Terminal is currently suspended")
> >                       nil ; The sequence will be sent upon resume.
> >                     (signal (car err) (cdr err)))))
> > -        (push enable (terminal-parameter nil 'tty-mode-set-strings))
> > -        (push disable (terminal-parameter nil 'tty-mode-reset-strings))
> > +        (push enable (terminal-parameter terminal 'tty-mode-set-strings))
> > +        (push sync (terminal-parameter terminal 'tty-mode-reset-strings))
> > +        (push disable (terminal-parameter terminal 'tty-mode-reset-strings))
> > +        (puthash terminal (list enable disable sync) xterm-mouse--terminals)
> >          (set-terminal-parameter terminal 'xterm-mouse-mode t)
> >          (set-terminal-parameter terminal 'xterm-mouse-utf-8
> >                                  xterm-mouse-utf-8)))))
> >  
> > +(declare-function xterm--read-string "xterm" (sequence &optional unread-all-events))
> > +
> > +(defun xterm-mouse--sync (terminal)
> > +  "Ensure that the TERMINAL is in a synchronized state, but obey
> > +xterm-query-timeout.
> > +
> > +When the sequence to disable mouse tracking has been sent and this
> > +function returns successfully, no further mouse events should be
> > +produced."
> > +  (send-string-to-terminal "\e[0c" terminal)
> > +  (xterm--read-string "\e[?" t)
> > +  (xterm--read-string "c"))
> > +
> >  (defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
> >    "Disable xterm mouse tracking on TERMINAL."
> >    ;; Only send the disable command to those terminals to which we've already
> > @@ -544,18 +564,22 @@ turn-off-xterm-mouse-tracking-on-terminal
> >      ;; to send it too few times (or to fail to let xterm-mouse events
> >      ;; pass by untranslated).
> >      (condition-case err
> > -        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> > -                                 terminal)
> > +        (progn
> > +          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> > +                                   terminal)
> > +          (xterm-mouse--sync terminal))
> >        ;; FIXME: This should use a dedicated error signal.
> >        (error (if (equal (cadr err) "Terminal is currently suspended")
> >                   nil
> >                 (signal (car err) (cdr err)))))
> > -    (setf (terminal-parameter nil 'tty-mode-set-strings)
> > -          (remq xterm-mouse-tracking-enable-sequence
> > -                (terminal-parameter nil 'tty-mode-set-strings)))
> > -    (setf (terminal-parameter nil 'tty-mode-reset-strings)
> > -          (remq xterm-mouse-tracking-disable-sequence
> > -                (terminal-parameter nil 'tty-mode-reset-strings)))
> > +    (dolist (el (gethash terminal xterm-mouse--terminals))
> > +      (setf (terminal-parameter terminal 'tty-mode-set-strings)
> > +            (remq el
> > +                  (terminal-parameter terminal 'tty-mode-set-strings)))
> > +      (setf (terminal-parameter terminal 'tty-mode-reset-strings)
> > +            (remq el
> > +                  (terminal-parameter terminal 'tty-mode-reset-strings))))
> > +    (remhash terminal xterm-mouse--terminals)
> >      (set-terminal-parameter terminal 'xterm-mouse-mode nil)))
> >  
> >  (provide 'xt-mouse)
> > 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
> > diff --git a/src/emacs.c b/src/emacs.c
> > index cf8f4bd63f7..ac81886f206 100644
> > --- a/src/emacs.c
> > +++ b/src/emacs.c
> > @@ -460,6 +460,8 @@ terminate_due_to_signal (int sig, int backtrace_limit)
> >  	      Fkill_emacs (make_fixnum (sig), Qnil);
> >  	    }
> >  
> > +	  /* Prevent running of Lisp code from now on.  */
> > +	  inhibit_lisp_code = Qt;
> >            shut_down_emacs (sig, Qnil);
> >            emacs_backtrace (backtrace_limit);
> >          }
> > @@ -3093,6 +3095,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
> >    fflush (stdout);
> >    reset_all_sys_modes ();
> >  #endif
> > +  inhibit_lisp_code = Qt;
> >  
> >    stuff_buffered_input (stuff);
> >  
> > diff --git a/src/eval.c b/src/eval.c
> > index 4c514001d9d..d7d3b109bc6 100644
> > --- a/src/eval.c
> > +++ b/src/eval.c
> > @@ -3187,6 +3187,8 @@ safe_eval (Lisp_Object sexp)
> >    return safe_calln (Qeval, sexp, Qt);
> >  }
> >  
> > +Lisp_Object inhibit_lisp_code;
> > +
> >  /* Apply a C subroutine SUBR to the NUMARGS evaluated arguments in ARG_VECTOR
> >     and return the result of evaluation.  */
> >  
> > @@ -4554,6 +4556,9 @@ syms_of_eval (void)
> >    staticpro (&list_of_t);
> >    list_of_t = list1 (Qt);
> >  
> > +  inhibit_lisp_code = Qnil;
> > +  staticpro (&inhibit_lisp_code);
> > +
> >    defsubr (&Sor);
> >    defsubr (&Sand);
> >    defsubr (&Sif);
> > diff --git a/src/keyboard.c b/src/keyboard.c
> > index fcb66f4c58a..ed346135aaa 100644
> > --- a/src/keyboard.c
> > +++ b/src/keyboard.c
> > @@ -12293,7 +12293,10 @@ handle_interrupt (bool in_signal_handler)
> >  	  fflush (stdout);
> >  	}
> >  
> > +      Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> > +      inhibit_lisp_code = Qt;
> >        reset_all_sys_modes ();
> > +      inhibit_lisp_code = old_inhibit_lisp_code;
> >  
> >  #ifdef SIGTSTP
> >  /*
> > diff --git a/src/term.c b/src/term.c
> > index 8aa47322d19..cd6ed09c29a 100644
> > --- a/src/term.c
> > +++ b/src/term.c
> > @@ -194,6 +194,10 @@ tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
> >            if (tty->termscript)
> >  	    fwrite (SDATA (string), 1, sbytes, tty->termscript);
> >          }
> > +      else if (NILP (inhibit_lisp_code) && FUNCTIONP (string))
> > +	{
> > +	  safe_calln (string);
> > +	}
> >      }
> >  }
> >  
> > @@ -2415,14 +2419,16 @@ DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
> >  
> >    if (f)
> >      {
> > -      /* First run `suspend-tty-functions' and then clean up the tty
> > -	 state because `suspend-tty-functions' might need to change
> > -	 the tty state.  */
> > +      /* The Emacs server uses `suspend-tty-functions' to perform the
> > +	 actual suspension of secondary terminals.  Therefore, we must
> > +	 run them after resetting the terminal state.  */
> >        Lisp_Object term;
> >        XSETTERMINAL (term, t);
> > -      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
> >  
> >        reset_sys_modes (t->display_info.tty);
> > +
> > +      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
> > +
> >        delete_keyboard_wait_descriptor (fileno (f));
> >  
> >  #ifndef MSDOS
> > @@ -4861,6 +4867,8 @@ vfatal (const char *str, va_list ap)
> >  maybe_fatal (bool must_succeed, struct terminal *terminal,
> >  	     const char *str1, const char *str2, ...)
> >  {
> > +  Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> > +  inhibit_lisp_code = Qt;
> >    va_list ap;
> >    va_start (ap, str2);
> >  
> > @@ -4875,6 +4883,8 @@ maybe_fatal (bool must_succeed, struct terminal *terminal,
> >      vfatal (str2, ap);
> >    else
> >      verror (str1, ap);
> > +
> > +  inhibit_lisp_code = old_inhibit_lisp_code;
> >  }
> >  
> >  void
> > diff --git a/src/terminal.c b/src/terminal.c
> > index 668b8845029..6a2fa12f748 100644
> > --- a/src/terminal.c
> > +++ b/src/terminal.c
> > @@ -412,10 +412,15 @@ DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_terminal, 0, 2, 0,
> >    else
> >      safe_calln (Qrun_hook_with_args, Qdelete_terminal_functions, terminal);
> >  
> > +  Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> > +  if (EQ (force, Qnoelisp))
> > +    inhibit_lisp_code = Qt;
> >    if (t->delete_terminal_hook)
> >      (*t->delete_terminal_hook) (t);
> >    else
> >      delete_terminal (t);
> > +  if (EQ (force, Qnoelisp))
> > +    inhibit_lisp_code = old_inhibit_lisp_code;
> >  
> >    return Qnil;
> >  }
> > 
> > 
> 
> 
> 
> 




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 26 Jul 2025 08:17:31 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jul 26 04:17:31 2025
Received: from localhost ([127.0.0.1]:39581 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1ufa5x-00070R-P0
	for submit <at> debbugs.gnu.org; Sat, 26 Jul 2025 04:17:31 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:54302)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1ufa5u-000708-Gv
 for 78899 <at> debbugs.gnu.org; Sat, 26 Jul 2025 04:17:28 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1ufa5m-0000Cx-HQ; Sat, 26 Jul 2025 04:17:18 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=/17Q8YsBiXrp3hjSju+wRaS8hmC3CI3nO7SDcAPtR8E=; b=fJ9Lj9qyQorW
 HMR7V1cAqXDv/2YIuZggeHEA6sH1tsNELXx0Wxmmc7+rTueSLObPZy3XCEEm8bd3srVtLna2aJYPO
 1oI7EhhgiMLNo7ckvqsO33odmnhr3sMuHcrKBb/fYzkCEicki4HQUcpZwK+eJREP0rI1lI4eGrQIY
 caNmG/hCl/Vayo//+nMagcZKoTfcCpcvIUlLvVvADvSYL7honWEA5VrfmIfJMQUvvhpQYRuT/7ObB
 6cBP26WMYFVkiJstW2S55pcMAZlXMbUUsMKcenoegu+WGvF9Px6GKs6NbnMu2LZ1zMYvWBiwlhZkN
 HRJNg0c7AvTTNZhJFwLeaA==;
Date: Sat, 26 Jul 2025 11:17:15 +0300
Message-Id: <86a54r2wok.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Pip Cet <pipcet@HIDDEN>
In-Reply-To: <87qzypsibk.fsf@HIDDEN> (message from Pip Cet on Wed, 09
 Jul 2025 11:40:53 +0000)
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN> <86h5zw2klj.fsf@HIDDEN>
 <bc2ac5f04c0214ab53a0bd0f0f5e46b4@HIDDEN> <87qzypsibk.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, vincent@HIDDEN, 78899 <at> debbugs.gnu.org,
 jared@HIDDEN, monnier@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Ping!  Any further progress with this?

> Date: Wed, 09 Jul 2025 11:40:53 +0000
> From: Pip Cet <pipcet@HIDDEN>
> Cc: Eli Zaretskii <eliz@HIDDEN>, Stefan Monnier <monnier@HIDDEN>, vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> 
> "Jared Finder" <jared@HIDDEN> writes:
> 
> > On 2025-07-01 04:53, Eli Zaretskii wrote:
> >>> Date: Mon, 30 Jun 2025 22:47:45 +0000
> >>> From: Pip Cet <pipcet@HIDDEN>
> >>> Cc: vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> >>
> >> Thanks.  Jared and Stefan, any comments?
> >
> > Does the most recent proposed patch work when Emacs is used across
> > multiple terminals?
> 
> Probably not, no.  It doesn't even work for suspending a terminal.
> Working on something better, based on your suggestion below.
> 
> I'm not sure whether I'm doing it right, but if I create a second
> terminal with emacsclient -nw and suspend it with C-z, Emacs crashes.
> I've worked around that for now, but if it's not just a local problem,
> we should probably fix it.
> 
> (I also had xterm crash once while working on the selection code.
> Unfortunately, all I have is the single-line segfault report in dmesg,
> which isn't very helpful.)
> 
> > I expect it does not because kill-emacs-hook is
> > only run when Emacs is fully killed.  I think it'd be more appropriate
> > to add additional functionality to the terminal parameter
> > tty-reset-strings to ensure the message is processed.
> 
> I agree that it would be nice to push a function to the
> tty-mode-reset-strings terminal parameter, and run it from C if we can
> (we can't run Lisp from within an Emergency Escape).
> 
> This requires reordering two calls: suspend-tty-functions does the
> actual suspending in "emacsclient -nw" instances, so it can only be run
> after we reset the tty modes, and shut_down_emacs should not inhibit
> Lisp until after it has reset the sys modes .  There don't appear to be
> any other users that expect the order to be different.
> 
> > But there's a scary message there about these escape strings and the
> > emergency escape that I do not understand the ramifications of.
> 
> I think I understand what's being said there: we definitely need an
> additional flag to prevent any potentially dangerous activity such as
> running Lisp, or even inspecting Lisp data that might have mark bits
> that we might fail to account for.
> 
> I resurrected inhibit_lisp_code for this purpose.
> 
> I'm still seeing other problems on slow xterms: xterm--query's
> synchronous branch fails to work if other input arrives after the
> (discard-input) but before the response to our query, which means that
> if you start typing before the initial xterm--query calls complete,
> you'll get the background description as input.
> 
> Since the delay of running multiple synchronous queries is also
> significant, I think it would be best to switch to asynchronous
> xterm--query in all but two cases: the new synchronization method needs
> to be synchronous to ensure proper ordering, and the
> gui-backend-get-selection method needs to be synchronous because the API
> is.
> 
> There are also some minor improvements:
> 
> * turn-off-xterm-mouse-tracking-on-terminal now removes the sequences
> successfully.
> * xterm--query now uninstalls the input-decode-map binding when the
> timeout expires.
> 
> Here's a snapshot (including the workaround to make frame suspension
> works).
> 
> diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
> index 4f23a909b69..9618e44ea30 100644
> --- a/lisp/term/xterm.el
> +++ b/lisp/term/xterm.el
> @@ -743,9 +743,10 @@ xterm-standard-colors
>  
>  (defun xterm--report-background-handler ()
>    ;; The reply should be: \e ] 11 ; rgb: NUMBER1 / NUMBER2 / NUMBER3 \e \\
> -  (let ((str (xterm--read-string ?\e ?\\)))
> -    (when (string-match
> -           "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str)
> +  (let ((str (xterm--read-string "\e\\")))
> +    (when (and str
> +               (string-match
> +                "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str))
>        (let ((recompute-faces
>               (xterm-maybe-set-dark-background-mode
>                (string-to-number (match-string 1 str) 16)
> @@ -763,14 +764,10 @@ xterm--report-background-handler
>  
>  (defun xterm--version-handler ()
>    ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
> -  ;; If the timeout is completely removed for read-event, this
> -  ;; might hang for terminals that pretend to be xterm, but don't
> -  ;; respond to this escape sequence.  RMS' opinion was to remove
> -  ;; it completely.  That might be right, but let's first try to
> -  ;; see if by using a longer timeout we get rid of most issues.
> -  (let ((str (xterm--read-string ?c)))
> +  (let ((str (xterm--read-string "c")))
>      ;; Since xterm-280, the terminal type (NUMBER1) is now 41 instead of 0.
> -    (when (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str)
> +    (when (and str
> +               (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str))
>        (let ((version (string-to-number (match-string 2 str))))
>          (when (and (> version 2000)
>                     (or (equal (match-string 1 str) "1")
> @@ -816,6 +813,22 @@ xterm--version-handler
>            ;;(xterm--init-activate-get-selection)
>            (xterm--init-activate-set-selection))))))
>  
> +(defun xterm--name-and-version-handler ()
> +  ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
> +  ;; If the timeout is completely removed for read-event, this
> +  ;; might hang for terminals that pretend to be xterm, but don't
> +  ;; respond to this escape sequence.  RMS' opinion was to remove
> +  ;; it completely.  That might be right, but let's first try to
> +  ;; see if by using a longer timeout we get rid of most issues.
> +  (let ((str (xterm--read-string "\e\\")))
> +    (and str
> +         (not xterm-mouse-mode-called)
> +         ;; Only automatically enable xterm mouse on terminals
> +         ;; confirmed to still support all critical editing
> +         ;; workflows (bug#74833).
> +         (string-match-p xterm--auto-xt-mouse-allowed-names str)
> +         (xterm-mouse-mode 1))))
> +
>  (defvar xterm-query-timeout 2
>    "Seconds to wait for an answer from the terminal.
>  Can be nil to mean \"no timeout\".")
> @@ -823,100 +836,42 @@ xterm-query-timeout
>  (defvar xterm-query-redisplay-timeout 0.2
>    "Seconds to wait before allowing redisplay during terminal query." )
>  
> -(defun xterm--read-event-for-query ()
> +(defun xterm--read-event-for-query (end-time)
>    "Like `read-event', but inhibit redisplay.
>  
>  By not redisplaying right away for xterm queries, we can avoid
>  unsightly flashing during initialization.  Give up and redisplay
>  anyway if we've been waiting a little while."
> -  (let ((start-time (current-time)))
> +  (let* ((timeout (float-time (time-subtract end-time (current-time))))
> +         (first-timeout (min xterm-query-redisplay-timeout timeout))
> +         (second-timeout (- timeout first-timeout)))
>      (or (let ((inhibit-redisplay t))
> -          (read-event nil nil xterm-query-redisplay-timeout))
> -        (read-event nil nil
> -                    (and xterm-query-timeout
> -			 (max 0 (float-time
> -				 (time-subtract
> -				  xterm-query-timeout
> -				  (time-since start-time)))))))))
> -
> -(defun xterm--read-string (term1 &optional term2)
> -  "Read a string with terminating characters.
> -This uses `xterm--read-event-for-query' internally."
> -  (let ((str "")
> -        chr last)
> -    (while (and (setq last chr
> -                      chr (xterm--read-event-for-query))
> -                (if term2
> -                    (not (and (equal last term1) (equal chr term2)))
> -                  (not (equal chr term1))))
> -      (setq str (concat str (string chr))))
> -    (if term2
> -        (substring str 0 -1)
> -      str)))
> -
> -(defun xterm--query (query handlers &optional no-async)
> +          (read-event nil nil (max 0 first-timeout)))
> +        (read-event nil nil (max 0 second-timeout)))))
> +
> +(defun xterm--query (query handlers)
>    "Send QUERY string to the terminal and watch for a response.
>  HANDLERS is an alist with elements of the form (STRING . FUNCTION).
>  We run the first FUNCTION whose STRING matches the input events."
> -  ;; We used to query synchronously, but the need to use `discard-input' is
> -  ;; rather annoying (bug#6758).  Maybe we could always use the asynchronous
> -  ;; approach, but it's less tested.
> -  ;; FIXME: Merge the two branches.
> -  (let ((register
> -         (lambda (handlers)
> -           (dolist (handler handlers)
> -             (define-key input-decode-map (car handler)
> -               (lambda (&optional _prompt)
> -                 ;; Unregister the handler, since we don't expect
> -                 ;; further answers.
> -                 (dolist (handler handlers)
> -                   (define-key input-decode-map (car handler) nil))
> -                 (funcall (cdr handler))
> -                 []))))))
> -    (if (and (or (null xterm-query-timeout) (input-pending-p))
> -             (not no-async))
> -        (progn
> -          (funcall register handlers)
> -          (send-string-to-terminal query))
> -      ;; Pending input can be mistakenly returned by the calls to
> -      ;; read-event below: discard it.
> -      (discard-input)
> -      (send-string-to-terminal query)
> -      (while handlers
> -        (let ((handler (pop handlers))
> -              (i 0))
> -          (while (and (< i (length (car handler)))
> -                      (let ((evt (xterm--read-event-for-query)))
> -                        (if (and (null evt) (= i 0) (not no-async))
> -                            ;; Timeout on the first event: fallback on async.
> -                            (progn
> -                              (funcall register (cons handler handlers))
> -                              (setq handlers nil)
> -                              nil)
> -                          (or (eq evt (aref (car handler) i))
> -                              (progn (if evt (push evt unread-command-events))
> -                                     nil)))))
> -            (setq i (1+ i)))
> -          (if (= i (length (car handler)))
> -              (progn (setq handlers nil)
> -                     (funcall (cdr handler)))
> -            (while (> i 0)
> -              (push (aref (car handler) (setq i (1- i)))
> -                    unread-command-events))))))))
> -
> -(defun xterm--query-name-and-version ()
> -  "Get the terminal name and version string (XTVERSION)."
> -  ;; Reduce query timeout time. The default value causes a noticeable
> -  ;; startup delay on terminals that ignore the query.
> -  (let ((xterm-query-timeout 0.1))
> -    (catch 'result
> -      (xterm--query
> -       "\e[>0q"
> -       `(("\eP>|" . ,(lambda ()
> -                       ;; The reply should be: \e P > | STRING \e \\
> -                       (let ((str (xterm--read-string ?\e ?\\)))
> -                         (throw 'result str))))))
> -      nil)))
> +  (let (unregister-functions)
> +    (dolist (handler handlers)
> +      (let* ((binding
> +              (lambda (&optional _prompt)
> +                ;; Unregister the handlers, since we don't expect
> +                ;; further answers.
> +                (mapc #'funcall unregister-functions)
> +                (funcall (cdr handler))
> +                []))
> +             (unregister
> +              (lambda ()
> +                (when (eq (lookup-key input-decode-map (car handler))
> +                          binding)
> +                  (define-key input-decode-map (car handler) nil)))))
> +        (define-key input-decode-map (car handler) binding)
> +        (push unregister unregister-functions)))
> +    (send-string-to-terminal query)
> +    (run-with-timer xterm-query-timeout nil
> +                    (lambda () (mapc #'funcall unregister-functions)))))
>  
>  (defun xterm--push-map (map basemap)
>    ;; Use inheritance to let the main keymaps override those defaults.
> @@ -965,16 +920,9 @@ xterm--init
>  
>    (when xterm-set-window-title
>      (xterm--init-frame-title))
> -  (when (and (not xterm-mouse-mode-called)
> -             ;; Only automatically enable xterm mouse on terminals
> -             ;; confirmed to still support all critical editing
> -             ;; workflows (bug#74833).
> -             (or (string-match-p xterm--auto-xt-mouse-allowed-types
> -                                 (tty-type (selected-frame)))
> -                 (and-let* ((name-and-version (xterm--query-name-and-version)))
> -                   (string-match-p xterm--auto-xt-mouse-allowed-names
> -                                   name-and-version))))
> -    (xterm-mouse-mode 1))
> +  (when (not xterm-mouse-mode-called)
> +    (xterm--query "\e[>0q"
> +                  '(("\eP>|" . xterm--name-and-version-handler))))
>    ;; Unconditionally enable bracketed paste mode: terminals that don't
>    ;; support it just ignore the sequence.
>    (xterm--init-bracketed-paste-mode)
> @@ -1053,6 +1001,33 @@ xterm--selection-char
>      ('CLIPBOARD "c")
>      (_ (error "Invalid selection type: %S" type))))
>  
> +(defun xterm--read-string (sequence &optional unread-all-events)
> +  "Read input until we see SEQUENCE.  Return string of the input characters
> +before its appearance, or nil if we hit a timeout.  Non-characters are
> +stored in unread-command-events.  If UNREAD-ALL-EVENTS is non-nil, all
> +events are stored there."
> +  (setq sequence (nreverse (append sequence nil)))
> +  (let ((end-time (time-add (current-time) xterm-query-timeout))
> +        (n (length sequence))
> +        events chars ret)
> +    (unwind-protect
> +        (catch 'failure
> +          (while (not (equal (take n chars) sequence))
> +            (let ((event (xterm--read-event-for-query end-time)))
> +              (if event
> +                  (push event events)
> +                (throw 'failure nil))
> +              (when (characterp event)
> +                (push event chars))))
> +          (setq ret (concat (nreverse (nthcdr n chars)))))
> +      (dolist (event events)
> +        (cond ((eq event (car sequence))
> +               (pop sequence))
> +              ((or (not (characterp event))
> +                   (not (stringp ret))
> +                   unread-all-events)
> +               (push event unread-command-events)))))))
> +
>  (cl-defmethod gui-backend-get-selection
>      (type data-type
>       &context (window-system nil)
> @@ -1064,27 +1039,16 @@ gui-backend-get-selection
>                 (eql nil)))
>    (unless (eq data-type 'STRING)
>      (error "Unsupported data type %S" data-type))
> -  (let ((query (concat "\e]52;" (xterm--selection-char type) ";")))
> -    (with-temp-buffer
> +  (with-temp-buffer
> +    (let* ((query (concat "\e]52;" (xterm--selection-char type) ";")))
>        (set-buffer-multibyte nil)
> -      (xterm--query
> -       ;; Use ST as query terminator to get ST as reply terminator (bug#36879).
> -       (concat query "?\e\\")
> -       (list (cons query
> -                   (lambda ()
> -                     ;; Read data up to the string terminator, ST.
> -                     (let (char last)
> -                       (while (and (setq char (read-char
> -                                               nil nil
> -                                               xterm-query-timeout))
> -                                   (not (and (eq char ?\\)
> -                                             (eq last ?\e))))
> -                         (when last
> -                           (insert last))
> -                         (setq last char))))))
> -       'no-async)
> -      (base64-decode-region (point-min) (point-max))
> -      (decode-coding-region (point-min) (point-max) 'utf-8-unix t))))
> +      (send-string-to-terminal (concat query "?\e\\"))
> +      (xterm--read-string query t)
> +      (let ((str (xterm--read-string "\e\\")))
> +        (when str
> +          (insert str)
> +          (base64-decode-region (point-min) (point-max))
> +          (decode-coding-region (point-min) (point-max) 'utf-8-unix t))))))
>  
>  (cl-defmethod gui-backend-set-selection
>      (type data
> diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
> index 89f9bbab608..4a4cb3a37b3 100644
> --- a/lisp/xt-mouse.el
> +++ b/lisp/xt-mouse.el
> @@ -387,6 +387,9 @@ xterm-mouse-mode-called
>    "If `xterm-mouse-mode' has been called already.
>  This can be used to detect if xterm-mouse-mode was explicitly set.")
>  
> +(defvar xterm-mouse--terminals (make-hash-table :test 'eq :weakness 'key)
> +  "Hash table of cleanups to be performed when xterm-mouse-mode is disabled.")
> +
>  ;;;###autoload
>  (define-minor-mode xterm-mouse-mode
>    "Toggle XTerm mouse mode.
> @@ -507,6 +510,7 @@ xterm-mouse--tracking-sequence
>  
>  (defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal)
>    "Enable xterm mouse tracking on TERMINAL."
> +  (setq terminal (or terminal (frame-terminal)))
>    (when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
>  	     ;; Avoid the initial terminal which is not a termcap device.
>  	     ;; FIXME: is there more elegant way to detect the initial
> @@ -519,19 +523,35 @@ turn-on-xterm-mouse-tracking-on-terminal
>          (define-key input-decode-map "\e[M" 'xterm-mouse-translate)
>          (define-key input-decode-map "\e[<" 'xterm-mouse-translate-extended))
>        (let ((enable (xterm-mouse-tracking-enable-sequence))
> -            (disable (xterm-mouse-tracking-disable-sequence)))
> +            (disable (xterm-mouse-tracking-disable-sequence))
> +            (sync (lambda () (xterm-mouse--sync terminal))))
>          (condition-case err
>              (send-string-to-terminal enable terminal)
>            ;; FIXME: This should use a dedicated error signal.
>            (error (if (equal (cadr err) "Terminal is currently suspended")
>                       nil ; The sequence will be sent upon resume.
>                     (signal (car err) (cdr err)))))
> -        (push enable (terminal-parameter nil 'tty-mode-set-strings))
> -        (push disable (terminal-parameter nil 'tty-mode-reset-strings))
> +        (push enable (terminal-parameter terminal 'tty-mode-set-strings))
> +        (push sync (terminal-parameter terminal 'tty-mode-reset-strings))
> +        (push disable (terminal-parameter terminal 'tty-mode-reset-strings))
> +        (puthash terminal (list enable disable sync) xterm-mouse--terminals)
>          (set-terminal-parameter terminal 'xterm-mouse-mode t)
>          (set-terminal-parameter terminal 'xterm-mouse-utf-8
>                                  xterm-mouse-utf-8)))))
>  
> +(declare-function xterm--read-string "xterm" (sequence &optional unread-all-events))
> +
> +(defun xterm-mouse--sync (terminal)
> +  "Ensure that the TERMINAL is in a synchronized state, but obey
> +xterm-query-timeout.
> +
> +When the sequence to disable mouse tracking has been sent and this
> +function returns successfully, no further mouse events should be
> +produced."
> +  (send-string-to-terminal "\e[0c" terminal)
> +  (xterm--read-string "\e[?" t)
> +  (xterm--read-string "c"))
> +
>  (defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
>    "Disable xterm mouse tracking on TERMINAL."
>    ;; Only send the disable command to those terminals to which we've already
> @@ -544,18 +564,22 @@ turn-off-xterm-mouse-tracking-on-terminal
>      ;; to send it too few times (or to fail to let xterm-mouse events
>      ;; pass by untranslated).
>      (condition-case err
> -        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> -                                 terminal)
> +        (progn
> +          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> +                                   terminal)
> +          (xterm-mouse--sync terminal))
>        ;; FIXME: This should use a dedicated error signal.
>        (error (if (equal (cadr err) "Terminal is currently suspended")
>                   nil
>                 (signal (car err) (cdr err)))))
> -    (setf (terminal-parameter nil 'tty-mode-set-strings)
> -          (remq xterm-mouse-tracking-enable-sequence
> -                (terminal-parameter nil 'tty-mode-set-strings)))
> -    (setf (terminal-parameter nil 'tty-mode-reset-strings)
> -          (remq xterm-mouse-tracking-disable-sequence
> -                (terminal-parameter nil 'tty-mode-reset-strings)))
> +    (dolist (el (gethash terminal xterm-mouse--terminals))
> +      (setf (terminal-parameter terminal 'tty-mode-set-strings)
> +            (remq el
> +                  (terminal-parameter terminal 'tty-mode-set-strings)))
> +      (setf (terminal-parameter terminal 'tty-mode-reset-strings)
> +            (remq el
> +                  (terminal-parameter terminal 'tty-mode-reset-strings))))
> +    (remhash terminal xterm-mouse--terminals)
>      (set-terminal-parameter terminal 'xterm-mouse-mode nil)))
>  
>  (provide 'xt-mouse)
> 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
> diff --git a/src/emacs.c b/src/emacs.c
> index cf8f4bd63f7..ac81886f206 100644
> --- a/src/emacs.c
> +++ b/src/emacs.c
> @@ -460,6 +460,8 @@ terminate_due_to_signal (int sig, int backtrace_limit)
>  	      Fkill_emacs (make_fixnum (sig), Qnil);
>  	    }
>  
> +	  /* Prevent running of Lisp code from now on.  */
> +	  inhibit_lisp_code = Qt;
>            shut_down_emacs (sig, Qnil);
>            emacs_backtrace (backtrace_limit);
>          }
> @@ -3093,6 +3095,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
>    fflush (stdout);
>    reset_all_sys_modes ();
>  #endif
> +  inhibit_lisp_code = Qt;
>  
>    stuff_buffered_input (stuff);
>  
> diff --git a/src/eval.c b/src/eval.c
> index 4c514001d9d..d7d3b109bc6 100644
> --- a/src/eval.c
> +++ b/src/eval.c
> @@ -3187,6 +3187,8 @@ safe_eval (Lisp_Object sexp)
>    return safe_calln (Qeval, sexp, Qt);
>  }
>  
> +Lisp_Object inhibit_lisp_code;
> +
>  /* Apply a C subroutine SUBR to the NUMARGS evaluated arguments in ARG_VECTOR
>     and return the result of evaluation.  */
>  
> @@ -4554,6 +4556,9 @@ syms_of_eval (void)
>    staticpro (&list_of_t);
>    list_of_t = list1 (Qt);
>  
> +  inhibit_lisp_code = Qnil;
> +  staticpro (&inhibit_lisp_code);
> +
>    defsubr (&Sor);
>    defsubr (&Sand);
>    defsubr (&Sif);
> diff --git a/src/keyboard.c b/src/keyboard.c
> index fcb66f4c58a..ed346135aaa 100644
> --- a/src/keyboard.c
> +++ b/src/keyboard.c
> @@ -12293,7 +12293,10 @@ handle_interrupt (bool in_signal_handler)
>  	  fflush (stdout);
>  	}
>  
> +      Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> +      inhibit_lisp_code = Qt;
>        reset_all_sys_modes ();
> +      inhibit_lisp_code = old_inhibit_lisp_code;
>  
>  #ifdef SIGTSTP
>  /*
> diff --git a/src/term.c b/src/term.c
> index 8aa47322d19..cd6ed09c29a 100644
> --- a/src/term.c
> +++ b/src/term.c
> @@ -194,6 +194,10 @@ tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
>            if (tty->termscript)
>  	    fwrite (SDATA (string), 1, sbytes, tty->termscript);
>          }
> +      else if (NILP (inhibit_lisp_code) && FUNCTIONP (string))
> +	{
> +	  safe_calln (string);
> +	}
>      }
>  }
>  
> @@ -2415,14 +2419,16 @@ DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0, 1, 0,
>  
>    if (f)
>      {
> -      /* First run `suspend-tty-functions' and then clean up the tty
> -	 state because `suspend-tty-functions' might need to change
> -	 the tty state.  */
> +      /* The Emacs server uses `suspend-tty-functions' to perform the
> +	 actual suspension of secondary terminals.  Therefore, we must
> +	 run them after resetting the terminal state.  */
>        Lisp_Object term;
>        XSETTERMINAL (term, t);
> -      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
>  
>        reset_sys_modes (t->display_info.tty);
> +
> +      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
> +
>        delete_keyboard_wait_descriptor (fileno (f));
>  
>  #ifndef MSDOS
> @@ -4861,6 +4867,8 @@ vfatal (const char *str, va_list ap)
>  maybe_fatal (bool must_succeed, struct terminal *terminal,
>  	     const char *str1, const char *str2, ...)
>  {
> +  Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> +  inhibit_lisp_code = Qt;
>    va_list ap;
>    va_start (ap, str2);
>  
> @@ -4875,6 +4883,8 @@ maybe_fatal (bool must_succeed, struct terminal *terminal,
>      vfatal (str2, ap);
>    else
>      verror (str1, ap);
> +
> +  inhibit_lisp_code = old_inhibit_lisp_code;
>  }
>  
>  void
> diff --git a/src/terminal.c b/src/terminal.c
> index 668b8845029..6a2fa12f748 100644
> --- a/src/terminal.c
> +++ b/src/terminal.c
> @@ -412,10 +412,15 @@ DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_terminal, 0, 2, 0,
>    else
>      safe_calln (Qrun_hook_with_args, Qdelete_terminal_functions, terminal);
>  
> +  Lisp_Object old_inhibit_lisp_code = inhibit_lisp_code;
> +  if (EQ (force, Qnoelisp))
> +    inhibit_lisp_code = Qt;
>    if (t->delete_terminal_hook)
>      (*t->delete_terminal_hook) (t);
>    else
>      delete_terminal (t);
> +  if (EQ (force, Qnoelisp))
> +    inhibit_lisp_code = old_inhibit_lisp_code;
>  
>    return Qnil;
>  }
> 
> 




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 9 Jul 2025 11:41:24 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jul 09 07:41:24 2025
Received: from localhost ([127.0.0.1]:49277 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uZTAv-00027o-My
	for submit <at> debbugs.gnu.org; Wed, 09 Jul 2025 07:41:23 -0400
Received: from mail-4316.protonmail.ch ([185.70.43.16]:21689)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <pipcet@HIDDEN>)
 id 1uZTAh-000266-VY
 for 78899 <at> debbugs.gnu.org; Wed, 09 Jul 2025 07:41:15 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;
 s=protonmail3; t=1752061260; x=1752320460;
 bh=sPXYN01uJAXRuo4qXlR4kkbunyBirXBUMJRNjv9szew=;
 h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:
 Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:
 Message-ID:BIMI-Selector;
 b=CteMW3ouPVXUR1uzcTI9hZvHuJ2x//QWMFRizrOK4DP+JAgBnC0JaDG0FonV9idiP
 7OuZLeUdMzk/3yMRIXDJM0UrmgEUr3EA5wOTjKjyGHDEfNJHLYRdrpOW6CZoL+eSyz
 SQvtENMmw39fv3ZX0cnzscV9bx9fgR018mLzzOR+3sF37l88xFXuhciKZfK3Vs11Nt
 8Okpu5lBILMnSlaqVXDJ1CgXP2JubJBXZRy6HXkDRwy09izj88yDgLR7oMy+ARAk5K
 VRg33Ddm2WbkimOosooh93f2Tp/wFcb+UDm/vpV5x2J36A5NiQ+e5AR0lwGWdYBWyE
 7wt8ZMtP8MtUw==
Date: Wed, 09 Jul 2025 11:40:53 +0000
To: Jared Finder <jared@HIDDEN>
From: Pip Cet <pipcet@HIDDEN>
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
Message-ID: <87qzypsibk.fsf@HIDDEN>
In-Reply-To: <bc2ac5f04c0214ab53a0bd0f0f5e46b4@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN> <86h5zw2klj.fsf@HIDDEN>
 <bc2ac5f04c0214ab53a0bd0f0f5e46b4@HIDDEN>
Feedback-ID: 112775352:user:proton
X-Pm-Message-ID: b719d2a6a463ecdc69728f62c50aeab23ed6519e
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, Eli Zaretskii <eliz@HIDDEN>, vincent@HIDDEN,
 Stefan Monnier <monnier@HIDDEN>, 78899 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

"Jared Finder" <jared@HIDDEN> writes:

> On 2025-07-01 04:53, Eli Zaretskii wrote:
>>> Date: Mon, 30 Jun 2025 22:47:45 +0000
>>> From: Pip Cet <pipcet@HIDDEN>
>>> Cc: vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
>>
>> Thanks.  Jared and Stefan, any comments?
>
> Does the most recent proposed patch work when Emacs is used across
> multiple terminals?

Probably not, no.  It doesn't even work for suspending a terminal.
Working on something better, based on your suggestion below.

I'm not sure whether I'm doing it right, but if I create a second
terminal with emacsclient -nw and suspend it with C-z, Emacs crashes.
I've worked around that for now, but if it's not just a local problem,
we should probably fix it.

(I also had xterm crash once while working on the selection code.
Unfortunately, all I have is the single-line segfault report in dmesg,
which isn't very helpful.)

> I expect it does not because kill-emacs-hook is
> only run when Emacs is fully killed.  I think it'd be more appropriate
> to add additional functionality to the terminal parameter
> tty-reset-strings to ensure the message is processed.

I agree that it would be nice to push a function to the
tty-mode-reset-strings terminal parameter, and run it from C if we can
(we can't run Lisp from within an Emergency Escape).

This requires reordering two calls: suspend-tty-functions does the
actual suspending in "emacsclient -nw" instances, so it can only be run
after we reset the tty modes, and shut_down_emacs should not inhibit
Lisp until after it has reset the sys modes .  There don't appear to be
any other users that expect the order to be different.

> But there's a scary message there about these escape strings and the
> emergency escape that I do not understand the ramifications of.

I think I understand what's being said there: we definitely need an
additional flag to prevent any potentially dangerous activity such as
running Lisp, or even inspecting Lisp data that might have mark bits
that we might fail to account for.

I resurrected inhibit_lisp_code for this purpose.

I'm still seeing other problems on slow xterms: xterm--query's
synchronous branch fails to work if other input arrives after the
(discard-input) but before the response to our query, which means that
if you start typing before the initial xterm--query calls complete,
you'll get the background description as input.

Since the delay of running multiple synchronous queries is also
significant, I think it would be best to switch to asynchronous
xterm--query in all but two cases: the new synchronization method needs
to be synchronous to ensure proper ordering, and the
gui-backend-get-selection method needs to be synchronous because the API
is.

There are also some minor improvements:

* turn-off-xterm-mouse-tracking-on-terminal now removes the sequences
successfully.
* xterm--query now uninstalls the input-decode-map binding when the
timeout expires.

Here's a snapshot (including the workaround to make frame suspension
works).

diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 4f23a909b69..9618e44ea30 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -743,9 +743,10 @@ xterm-standard-colors
=20
 (defun xterm--report-background-handler ()
   ;; The reply should be: \e ] 11 ; rgb: NUMBER1 / NUMBER2 / NUMBER3 \e \\
-  (let ((str (xterm--read-string ?\e ?\\)))
-    (when (string-match
-           "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str)
+  (let ((str (xterm--read-string "\e\\")))
+    (when (and str
+               (string-match
+                "rgb:\\([a-f0-9]+\\)/\\([a-f0-9]+\\)/\\([a-f0-9]+\\)" str)=
)
       (let ((recompute-faces
              (xterm-maybe-set-dark-background-mode
               (string-to-number (match-string 1 str) 16)
@@ -763,14 +764,10 @@ xterm--report-background-handler
=20
 (defun xterm--version-handler ()
   ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
-  ;; If the timeout is completely removed for read-event, this
-  ;; might hang for terminals that pretend to be xterm, but don't
-  ;; respond to this escape sequence.  RMS' opinion was to remove
-  ;; it completely.  That might be right, but let's first try to
-  ;; see if by using a longer timeout we get rid of most issues.
-  (let ((str (xterm--read-string ?c)))
+  (let ((str (xterm--read-string "c")))
     ;; Since xterm-280, the terminal type (NUMBER1) is now 41 instead of 0=
.
-    (when (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str)
+    (when (and str
+               (string-match "\\([0-9]+\\);\\([0-9]+\\);[01]" str))
       (let ((version (string-to-number (match-string 2 str))))
         (when (and (> version 2000)
                    (or (equal (match-string 1 str) "1")
@@ -816,6 +813,22 @@ xterm--version-handler
           ;;(xterm--init-activate-get-selection)
           (xterm--init-activate-set-selection))))))
=20
+(defun xterm--name-and-version-handler ()
+  ;; The reply should be: \e [ > NUMBER1 ; NUMBER2 ; NUMBER3 c
+  ;; If the timeout is completely removed for read-event, this
+  ;; might hang for terminals that pretend to be xterm, but don't
+  ;; respond to this escape sequence.  RMS' opinion was to remove
+  ;; it completely.  That might be right, but let's first try to
+  ;; see if by using a longer timeout we get rid of most issues.
+  (let ((str (xterm--read-string "\e\\")))
+    (and str
+         (not xterm-mouse-mode-called)
+         ;; Only automatically enable xterm mouse on terminals
+         ;; confirmed to still support all critical editing
+         ;; workflows (bug#74833).
+         (string-match-p xterm--auto-xt-mouse-allowed-names str)
+         (xterm-mouse-mode 1))))
+
 (defvar xterm-query-timeout 2
   "Seconds to wait for an answer from the terminal.
 Can be nil to mean \"no timeout\".")
@@ -823,100 +836,42 @@ xterm-query-timeout
 (defvar xterm-query-redisplay-timeout 0.2
   "Seconds to wait before allowing redisplay during terminal query." )
=20
-(defun xterm--read-event-for-query ()
+(defun xterm--read-event-for-query (end-time)
   "Like `read-event', but inhibit redisplay.
=20
 By not redisplaying right away for xterm queries, we can avoid
 unsightly flashing during initialization.  Give up and redisplay
 anyway if we've been waiting a little while."
-  (let ((start-time (current-time)))
+  (let* ((timeout (float-time (time-subtract end-time (current-time))))
+         (first-timeout (min xterm-query-redisplay-timeout timeout))
+         (second-timeout (- timeout first-timeout)))
     (or (let ((inhibit-redisplay t))
-          (read-event nil nil xterm-query-redisplay-timeout))
-        (read-event nil nil
-                    (and xterm-query-timeout
-=09=09=09 (max 0 (float-time
-=09=09=09=09 (time-subtract
-=09=09=09=09  xterm-query-timeout
-=09=09=09=09  (time-since start-time)))))))))
-
-(defun xterm--read-string (term1 &optional term2)
-  "Read a string with terminating characters.
-This uses `xterm--read-event-for-query' internally."
-  (let ((str "")
-        chr last)
-    (while (and (setq last chr
-                      chr (xterm--read-event-for-query))
-                (if term2
-                    (not (and (equal last term1) (equal chr term2)))
-                  (not (equal chr term1))))
-      (setq str (concat str (string chr))))
-    (if term2
-        (substring str 0 -1)
-      str)))
-
-(defun xterm--query (query handlers &optional no-async)
+          (read-event nil nil (max 0 first-timeout)))
+        (read-event nil nil (max 0 second-timeout)))))
+
+(defun xterm--query (query handlers)
   "Send QUERY string to the terminal and watch for a response.
 HANDLERS is an alist with elements of the form (STRING . FUNCTION).
 We run the first FUNCTION whose STRING matches the input events."
-  ;; We used to query synchronously, but the need to use `discard-input' i=
s
-  ;; rather annoying (bug#6758).  Maybe we could always use the asynchrono=
us
-  ;; approach, but it's less tested.
-  ;; FIXME: Merge the two branches.
-  (let ((register
-         (lambda (handlers)
-           (dolist (handler handlers)
-             (define-key input-decode-map (car handler)
-               (lambda (&optional _prompt)
-                 ;; Unregister the handler, since we don't expect
-                 ;; further answers.
-                 (dolist (handler handlers)
-                   (define-key input-decode-map (car handler) nil))
-                 (funcall (cdr handler))
-                 []))))))
-    (if (and (or (null xterm-query-timeout) (input-pending-p))
-             (not no-async))
-        (progn
-          (funcall register handlers)
-          (send-string-to-terminal query))
-      ;; Pending input can be mistakenly returned by the calls to
-      ;; read-event below: discard it.
-      (discard-input)
-      (send-string-to-terminal query)
-      (while handlers
-        (let ((handler (pop handlers))
-              (i 0))
-          (while (and (< i (length (car handler)))
-                      (let ((evt (xterm--read-event-for-query)))
-                        (if (and (null evt) (=3D i 0) (not no-async))
-                            ;; Timeout on the first event: fallback on asy=
nc.
-                            (progn
-                              (funcall register (cons handler handlers))
-                              (setq handlers nil)
-                              nil)
-                          (or (eq evt (aref (car handler) i))
-                              (progn (if evt (push evt unread-command-even=
ts))
-                                     nil)))))
-            (setq i (1+ i)))
-          (if (=3D i (length (car handler)))
-              (progn (setq handlers nil)
-                     (funcall (cdr handler)))
-            (while (> i 0)
-              (push (aref (car handler) (setq i (1- i)))
-                    unread-command-events))))))))
-
-(defun xterm--query-name-and-version ()
-  "Get the terminal name and version string (XTVERSION)."
-  ;; Reduce query timeout time. The default value causes a noticeable
-  ;; startup delay on terminals that ignore the query.
-  (let ((xterm-query-timeout 0.1))
-    (catch 'result
-      (xterm--query
-       "\e[>0q"
-       `(("\eP>|" . ,(lambda ()
-                       ;; The reply should be: \e P > | STRING \e \\
-                       (let ((str (xterm--read-string ?\e ?\\)))
-                         (throw 'result str))))))
-      nil)))
+  (let (unregister-functions)
+    (dolist (handler handlers)
+      (let* ((binding
+              (lambda (&optional _prompt)
+                ;; Unregister the handlers, since we don't expect
+                ;; further answers.
+                (mapc #'funcall unregister-functions)
+                (funcall (cdr handler))
+                []))
+             (unregister
+              (lambda ()
+                (when (eq (lookup-key input-decode-map (car handler))
+                          binding)
+                  (define-key input-decode-map (car handler) nil)))))
+        (define-key input-decode-map (car handler) binding)
+        (push unregister unregister-functions)))
+    (send-string-to-terminal query)
+    (run-with-timer xterm-query-timeout nil
+                    (lambda () (mapc #'funcall unregister-functions)))))
=20
 (defun xterm--push-map (map basemap)
   ;; Use inheritance to let the main keymaps override those defaults.
@@ -965,16 +920,9 @@ xterm--init
=20
   (when xterm-set-window-title
     (xterm--init-frame-title))
-  (when (and (not xterm-mouse-mode-called)
-             ;; Only automatically enable xterm mouse on terminals
-             ;; confirmed to still support all critical editing
-             ;; workflows (bug#74833).
-             (or (string-match-p xterm--auto-xt-mouse-allowed-types
-                                 (tty-type (selected-frame)))
-                 (and-let* ((name-and-version (xterm--query-name-and-versi=
on)))
-                   (string-match-p xterm--auto-xt-mouse-allowed-names
-                                   name-and-version))))
-    (xterm-mouse-mode 1))
+  (when (not xterm-mouse-mode-called)
+    (xterm--query "\e[>0q"
+                  '(("\eP>|" . xterm--name-and-version-handler))))
   ;; Unconditionally enable bracketed paste mode: terminals that don't
   ;; support it just ignore the sequence.
   (xterm--init-bracketed-paste-mode)
@@ -1053,6 +1001,33 @@ xterm--selection-char
     ('CLIPBOARD "c")
     (_ (error "Invalid selection type: %S" type))))
=20
+(defun xterm--read-string (sequence &optional unread-all-events)
+  "Read input until we see SEQUENCE.  Return string of the input character=
s
+before its appearance, or nil if we hit a timeout.  Non-characters are
+stored in unread-command-events.  If UNREAD-ALL-EVENTS is non-nil, all
+events are stored there."
+  (setq sequence (nreverse (append sequence nil)))
+  (let ((end-time (time-add (current-time) xterm-query-timeout))
+        (n (length sequence))
+        events chars ret)
+    (unwind-protect
+        (catch 'failure
+          (while (not (equal (take n chars) sequence))
+            (let ((event (xterm--read-event-for-query end-time)))
+              (if event
+                  (push event events)
+                (throw 'failure nil))
+              (when (characterp event)
+                (push event chars))))
+          (setq ret (concat (nreverse (nthcdr n chars)))))
+      (dolist (event events)
+        (cond ((eq event (car sequence))
+               (pop sequence))
+              ((or (not (characterp event))
+                   (not (stringp ret))
+                   unread-all-events)
+               (push event unread-command-events)))))))
+
 (cl-defmethod gui-backend-get-selection
     (type data-type
      &context (window-system nil)
@@ -1064,27 +1039,16 @@ gui-backend-get-selection
                (eql nil)))
   (unless (eq data-type 'STRING)
     (error "Unsupported data type %S" data-type))
-  (let ((query (concat "\e]52;" (xterm--selection-char type) ";")))
-    (with-temp-buffer
+  (with-temp-buffer
+    (let* ((query (concat "\e]52;" (xterm--selection-char type) ";")))
       (set-buffer-multibyte nil)
-      (xterm--query
-       ;; Use ST as query terminator to get ST as reply terminator (bug#36=
879).
-       (concat query "?\e\\")
-       (list (cons query
-                   (lambda ()
-                     ;; Read data up to the string terminator, ST.
-                     (let (char last)
-                       (while (and (setq char (read-char
-                                               nil nil
-                                               xterm-query-timeout))
-                                   (not (and (eq char ?\\)
-                                             (eq last ?\e))))
-                         (when last
-                           (insert last))
-                         (setq last char))))))
-       'no-async)
-      (base64-decode-region (point-min) (point-max))
-      (decode-coding-region (point-min) (point-max) 'utf-8-unix t))))
+      (send-string-to-terminal (concat query "?\e\\"))
+      (xterm--read-string query t)
+      (let ((str (xterm--read-string "\e\\")))
+        (when str
+          (insert str)
+          (base64-decode-region (point-min) (point-max))
+          (decode-coding-region (point-min) (point-max) 'utf-8-unix t)))))=
)
=20
 (cl-defmethod gui-backend-set-selection
     (type data
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 89f9bbab608..4a4cb3a37b3 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -387,6 +387,9 @@ xterm-mouse-mode-called
   "If `xterm-mouse-mode' has been called already.
 This can be used to detect if xterm-mouse-mode was explicitly set.")
=20
+(defvar xterm-mouse--terminals (make-hash-table :test 'eq :weakness 'key)
+  "Hash table of cleanups to be performed when xterm-mouse-mode is disable=
d.")
+
 ;;;###autoload
 (define-minor-mode xterm-mouse-mode
   "Toggle XTerm mouse mode.
@@ -507,6 +510,7 @@ xterm-mouse--tracking-sequence
=20
 (defun turn-on-xterm-mouse-tracking-on-terminal (&optional terminal)
   "Enable xterm mouse tracking on TERMINAL."
+  (setq terminal (or terminal (frame-terminal)))
   (when (and xterm-mouse-mode (eq t (terminal-live-p terminal))
 =09     ;; Avoid the initial terminal which is not a termcap device.
 =09     ;; FIXME: is there more elegant way to detect the initial
@@ -519,19 +523,35 @@ turn-on-xterm-mouse-tracking-on-terminal
         (define-key input-decode-map "\e[M" 'xterm-mouse-translate)
         (define-key input-decode-map "\e[<" 'xterm-mouse-translate-extende=
d))
       (let ((enable (xterm-mouse-tracking-enable-sequence))
-            (disable (xterm-mouse-tracking-disable-sequence)))
+            (disable (xterm-mouse-tracking-disable-sequence))
+            (sync (lambda () (xterm-mouse--sync terminal))))
         (condition-case err
             (send-string-to-terminal enable terminal)
           ;; FIXME: This should use a dedicated error signal.
           (error (if (equal (cadr err) "Terminal is currently suspended")
                      nil ; The sequence will be sent upon resume.
                    (signal (car err) (cdr err)))))
-        (push enable (terminal-parameter nil 'tty-mode-set-strings))
-        (push disable (terminal-parameter nil 'tty-mode-reset-strings))
+        (push enable (terminal-parameter terminal 'tty-mode-set-strings))
+        (push sync (terminal-parameter terminal 'tty-mode-reset-strings))
+        (push disable (terminal-parameter terminal 'tty-mode-reset-strings=
))
+        (puthash terminal (list enable disable sync) xterm-mouse--terminal=
s)
         (set-terminal-parameter terminal 'xterm-mouse-mode t)
         (set-terminal-parameter terminal 'xterm-mouse-utf-8
                                 xterm-mouse-utf-8)))))
=20
+(declare-function xterm--read-string "xterm" (sequence &optional unread-al=
l-events))
+
+(defun xterm-mouse--sync (terminal)
+  "Ensure that the TERMINAL is in a synchronized state, but obey
+xterm-query-timeout.
+
+When the sequence to disable mouse tracking has been sent and this
+function returns successfully, no further mouse events should be
+produced."
+  (send-string-to-terminal "\e[0c" terminal)
+  (xterm--read-string "\e[?" t)
+  (xterm--read-string "c"))
+
 (defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
   "Disable xterm mouse tracking on TERMINAL."
   ;; Only send the disable command to those terminals to which we've alrea=
dy
@@ -544,18 +564,22 @@ turn-off-xterm-mouse-tracking-on-terminal
     ;; to send it too few times (or to fail to let xterm-mouse events
     ;; pass by untranslated).
     (condition-case err
-        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
-                                 terminal)
+        (progn
+          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
+                                   terminal)
+          (xterm-mouse--sync terminal))
       ;; FIXME: This should use a dedicated error signal.
       (error (if (equal (cadr err) "Terminal is currently suspended")
                  nil
                (signal (car err) (cdr err)))))
-    (setf (terminal-parameter nil 'tty-mode-set-strings)
-          (remq xterm-mouse-tracking-enable-sequence
-                (terminal-parameter nil 'tty-mode-set-strings)))
-    (setf (terminal-parameter nil 'tty-mode-reset-strings)
-          (remq xterm-mouse-tracking-disable-sequence
-                (terminal-parameter nil 'tty-mode-reset-strings)))
+    (dolist (el (gethash terminal xterm-mouse--terminals))
+      (setf (terminal-parameter terminal 'tty-mode-set-strings)
+            (remq el
+                  (terminal-parameter terminal 'tty-mode-set-strings)))
+      (setf (terminal-parameter terminal 'tty-mode-reset-strings)
+            (remq el
+                  (terminal-parameter terminal 'tty-mode-reset-strings))))
+    (remhash terminal xterm-mouse--terminals)
     (set-terminal-parameter terminal 'xterm-mouse-mode nil)))
=20
 (provide 'xt-mouse)
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 visi=
ble_only)
   struct frame *root =3D root_frame (f);
   Lisp_Object frames =3D frames_with_root (root, visible_only);
   frames =3D CALLN (Fsort, frames, QClessp, Qframe__z_order_lessp);
-  eassert (FRAMEP (XCAR (frames)));
-  eassert (XFRAME (XCAR (frames)) =3D=3D root);
+  eassert (NILP (frames) || FRAMEP (XCAR (frames)));
+  eassert (NILP (frames) || XFRAME (XCAR (frames)) =3D=3D root);
   return frames;
 }
=20
@@ -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 =3D frames_in_reverse_z_order (f, true);
-  return CONSP (XCDR (z_order));
+  return CONSP (z_order) && CONSP (XCDR (z_order));
 }
=20
 /* Return the index of the first enabled row in MATRIX, or -1 if there
diff --git a/src/emacs.c b/src/emacs.c
index cf8f4bd63f7..ac81886f206 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -460,6 +460,8 @@ terminate_due_to_signal (int sig, int backtrace_limit)
 =09      Fkill_emacs (make_fixnum (sig), Qnil);
 =09    }
=20
+=09  /* Prevent running of Lisp code from now on.  */
+=09  inhibit_lisp_code =3D Qt;
           shut_down_emacs (sig, Qnil);
           emacs_backtrace (backtrace_limit);
         }
@@ -3093,6 +3095,7 @@ shut_down_emacs (int sig, Lisp_Object stuff)
   fflush (stdout);
   reset_all_sys_modes ();
 #endif
+  inhibit_lisp_code =3D Qt;
=20
   stuff_buffered_input (stuff);
=20
diff --git a/src/eval.c b/src/eval.c
index 4c514001d9d..d7d3b109bc6 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3187,6 +3187,8 @@ safe_eval (Lisp_Object sexp)
   return safe_calln (Qeval, sexp, Qt);
 }
=20
+Lisp_Object inhibit_lisp_code;
+
 /* Apply a C subroutine SUBR to the NUMARGS evaluated arguments in ARG_VEC=
TOR
    and return the result of evaluation.  */
=20
@@ -4554,6 +4556,9 @@ syms_of_eval (void)
   staticpro (&list_of_t);
   list_of_t =3D list1 (Qt);
=20
+  inhibit_lisp_code =3D Qnil;
+  staticpro (&inhibit_lisp_code);
+
   defsubr (&Sor);
   defsubr (&Sand);
   defsubr (&Sif);
diff --git a/src/keyboard.c b/src/keyboard.c
index fcb66f4c58a..ed346135aaa 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -12293,7 +12293,10 @@ handle_interrupt (bool in_signal_handler)
 =09  fflush (stdout);
 =09}
=20
+      Lisp_Object old_inhibit_lisp_code =3D inhibit_lisp_code;
+      inhibit_lisp_code =3D Qt;
       reset_all_sys_modes ();
+      inhibit_lisp_code =3D old_inhibit_lisp_code;
=20
 #ifdef SIGTSTP
 /*
diff --git a/src/term.c b/src/term.c
index 8aa47322d19..cd6ed09c29a 100644
--- a/src/term.c
+++ b/src/term.c
@@ -194,6 +194,10 @@ tty_send_additional_strings (struct terminal *terminal=
, Lisp_Object sym)
           if (tty->termscript)
 =09    fwrite (SDATA (string), 1, sbytes, tty->termscript);
         }
+      else if (NILP (inhibit_lisp_code) && FUNCTIONP (string))
+=09{
+=09  safe_calln (string);
+=09}
     }
 }
=20
@@ -2415,14 +2419,16 @@ DEFUN ("suspend-tty", Fsuspend_tty, Ssuspend_tty, 0=
, 1, 0,
=20
   if (f)
     {
-      /* First run `suspend-tty-functions' and then clean up the tty
-=09 state because `suspend-tty-functions' might need to change
-=09 the tty state.  */
+      /* The Emacs server uses `suspend-tty-functions' to perform the
+=09 actual suspension of secondary terminals.  Therefore, we must
+=09 run them after resetting the terminal state.  */
       Lisp_Object term;
       XSETTERMINAL (term, t);
-      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
=20
       reset_sys_modes (t->display_info.tty);
+
+      CALLN (Frun_hook_with_args, Qsuspend_tty_functions, term);
+
       delete_keyboard_wait_descriptor (fileno (f));
=20
 #ifndef MSDOS
@@ -4861,6 +4867,8 @@ vfatal (const char *str, va_list ap)
 maybe_fatal (bool must_succeed, struct terminal *terminal,
 =09     const char *str1, const char *str2, ...)
 {
+  Lisp_Object old_inhibit_lisp_code =3D inhibit_lisp_code;
+  inhibit_lisp_code =3D Qt;
   va_list ap;
   va_start (ap, str2);
=20
@@ -4875,6 +4883,8 @@ maybe_fatal (bool must_succeed, struct terminal *term=
inal,
     vfatal (str2, ap);
   else
     verror (str1, ap);
+
+  inhibit_lisp_code =3D old_inhibit_lisp_code;
 }
=20
 void
diff --git a/src/terminal.c b/src/terminal.c
index 668b8845029..6a2fa12f748 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -412,10 +412,15 @@ DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_t=
erminal, 0, 2, 0,
   else
     safe_calln (Qrun_hook_with_args, Qdelete_terminal_functions, terminal)=
;
=20
+  Lisp_Object old_inhibit_lisp_code =3D inhibit_lisp_code;
+  if (EQ (force, Qnoelisp))
+    inhibit_lisp_code =3D Qt;
   if (t->delete_terminal_hook)
     (*t->delete_terminal_hook) (t);
   else
     delete_terminal (t);
+  if (EQ (force, Qnoelisp))
+    inhibit_lisp_code =3D old_inhibit_lisp_code;
=20
   return Qnil;
 }





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 5 Jul 2025 20:20:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Jul 05 16:20:39 2025
Received: from localhost ([127.0.0.1]:47611 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uY9NF-0000oz-0M
	for submit <at> debbugs.gnu.org; Sat, 05 Jul 2025 16:20:39 -0400
Received: from greenhill.hpalace.com ([192.155.80.58]:56782)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <jared@HIDDEN>) id 1uY9N9-0000nr-QM
 for 78899 <at> debbugs.gnu.org; Sat, 05 Jul 2025 16:20:33 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=finder.org; s=2018;
 t=1751746830; bh=rl+lgezQssQHtMcIZ7hDLtAfZ0r8BZwFvkJ24XGAVUk=;
 h=Date:From:To:Cc:Subject:In-Reply-To:References:From;
 b=pL+n8vgG/nsPlmR5fGAo+W2SP1ghMZ3XW7BdJLQZZDbhKT7K6cCvbuioN1aS0kaw8
 dfIAQGD1qGf6frjAmgXgdjTrylvNhcq/3q2Hb2yfbRWhRwwapf927cBuh0St7W0Gcr
 Czgwa1l3RqriOSQvekqRJ6jQGsSQFXqtr3b8CSOTr4teenrLKI0Y4BOth2FG0wl6sP
 45ZQqznNFZtRjFCYRZ+9V4YR1JrdHd2W5F5mN5eA9WHKgmQM+A+jJ85W+MnGApZoa/
 0FAjC8qTg9jqfBYFGCLv/f9CwxEGbag5A0BOOBVzcj9P3mXq1PJAbAcNr30s1bRA92
 n/mfYfiH2QBfQ==
Received: from mail.finder.org (unknown [192.155.80.58])
 by greenhill.hpalace.com (Postfix) with ESMTPSA id 7C6E41014;
 Sat,  5 Jul 2025 20:20:30 +0000 (UTC)
MIME-Version: 1.0
Date: Sat, 05 Jul 2025 13:20:30 -0700
From: Jared Finder <jared@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#78899: 30.1; garbage inserted in the terminal buffer when
 quitting Emacs
In-Reply-To: <86h5zw2klj.fsf@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN> <86h5zw2klj.fsf@HIDDEN>
Message-ID: <bc2ac5f04c0214ab53a0bd0f0f5e46b4@HIDDEN>
X-Sender: jared@HIDDEN
Content-Type: text/plain; charset=US-ASCII;
 format=flowed
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.2 (/)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, Pip Cet <pipcet@HIDDEN>, vincent@HIDDEN,
 Stefan Monnier <monnier@HIDDEN>, 78899 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.8 (/)

(I appear to have gotten dropped off the bug thread.)

On 2025-07-01 04:53, Eli Zaretskii wrote:
>> Date: Mon, 30 Jun 2025 22:47:45 +0000
>> From: Pip Cet <pipcet@HIDDEN>
>> Cc: vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> 
> Thanks.  Jared and Stefan, any comments?

Does the most recent proposed patch work when Emacs is used across 
multiple terminals?  I expect it does not because kill-emacs-hook is 
only run when Emacs is fully killed.  I think it'd be more appropriate 
to add additional functionality to the terminal parameter 
tty-reset-strings to ensure the message is processed.  But there's a 
scary message there about these escape strings and the emergency escape 
that I do not understand the ramifications of.

   -- MJF




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 2 Jul 2025 10:57:55 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jul 02 06:57:55 2025
Received: from localhost ([127.0.0.1]:35871 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uWvA2-0001h0-7B
	for submit <at> debbugs.gnu.org; Wed, 02 Jul 2025 06:57:54 -0400
Received: from mail-4322.protonmail.ch ([185.70.43.22]:34537)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <pipcet@HIDDEN>)
 id 1uWv9y-0001fr-JJ
 for 78899 <at> debbugs.gnu.org; Wed, 02 Jul 2025 06:57:52 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;
 s=protonmail3; t=1751453863; x=1751713063;
 bh=HYOzxA9YlD0PVl7sOXxlmonYzacm2/xo/Un8S6xu9r4=;
 h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:
 Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:
 Message-ID:BIMI-Selector;
 b=h7Dz/UN9xanxNpuLi6y1smg4oDuS982nJNkNd0hCOKdaV2cPrw/trh15lhl4QrY96
 gz4cGbl0uHu8lpgyTo+q77DhySgYoyNy7m1NVpH0gpzwWk37mSM0Te09LHQHM683zY
 c9E6JL2nlaBpJHOcV/nA849elbFA1yvrPzRNHU2YBKx02dj1QRT0a4681rmfZXwCGu
 BDxpzcQb2f588Yg8zQkNvUktd3MzB8+CCT+m50+aQKYVvtMGcDJseQH5bfQocJSRP2
 kqfebpQpncEEpyHgDYzav2OpAjDtE1dkdGzm7pka+l9mze6wCabD58PKdVrsy8y53W
 bmD5vJYV/1LaA==
Date: Wed, 02 Jul 2025 10:57:41 +0000
To: Stefan Monnier <monnier@HIDDEN>
From: Pip Cet <pipcet@HIDDEN>
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
Message-ID: <87zfdmx3ky.fsf@HIDDEN>
In-Reply-To: <jwvcyaj60xi.fsf-monnier+emacs@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN> <jwvcyaj60xi.fsf-monnier+emacs@HIDDEN>
Feedback-ID: 112775352:user:proton
X-Pm-Message-ID: 37d761448bac6f0f787642d29560370e39bdb033
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, Eli Zaretskii <eliz@HIDDEN>, vincent@HIDDEN,
 78899 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

"Stefan Monnier" <monnier@HIDDEN> writes:

>> * lisp/term/xterm.el (xterm--query-name-and-version): Accept
>> 'callback' argument.  Call it.
>> (xterm--init): Handle asynchronous terminal id responses.
>
> Hmm... you may want to check the code history, because I have a vague
> recollection that we had something along these lines at some point and
> it bumped into other problems, probably when ELisp code runs between
> `xterm--query-name-and-version` and its callback, and sends other things
> to the terminal or reads from the terminal.
>
> Maybe I misremember, of course.

Thanks!

Maybe a conditional throw would be better?  I don't think it's a problem
that we don't recognize xterms which are so slow to respond that
mouse-mode would be painful to use, anyway (it certainly is over tor).

>> +(defun xterm-sync (terminal &optional timeout)
>> +  "Ensure that the TERMINAL is in a synchronized state, but obey TIMEOU=
T."
>> +  ;; This function tries very hard to handle all events that do not bel=
ong
>> +  ;; to the escape sequence we are looking for.  It's usually called on=
ly
>> +  ;; when Emacs quits, so this might be overkill.
>> +  (setq timeout (or timeout 2.0))
>> +  (let ((i 0)
>> +        events all-events)
>> +    ;; request Primary DA from terminal
>> +    (send-string-to-terminal "\e[0c" terminal)
>> +    ;; build two lists: ALL-EVENTS contains all events, while EVENTS
>> +    ;; associates character events (only) to their index in ALL-EVENTS.
>> +    ;; We filter out the expected escape sequence ("\e[?") from the
>> +    ;; ALL-EVENTS list.
>> +    (with-timeout (timeout
>> +                   (setq unread-command-events
>> +                         (append unread-command-events
>> +                                 (nreverse all-events))))
>> +      (while (not
>> +              (pcase events
>> +                (`((?? . ,i0)
>> +                   (?\[ . ,i1)
>> +                   (?\e . ,i2) . ,_)
>> +                 (setq all-events (nreverse all-events))
>> +                 (pop (nthcdr i0 all-events))
>> +                 (pop (nthcdr i1 all-events))
>> +                 (pop (nthcdr i2 all-events))
>> +                 t)))
>> +        (let ((event (read-event)))
>> +          (push event all-events)
>> +          (when (characterp event)
>> +            (push (cons event i) events))
>> +          (incf i)))
>> +      ;; read the rest of the response
>> +      (xterm--read-string ?c)
>> +      ;; replay events that preceded or occurred within the escape
>> +      ;; sequence.
>> +      (setq unread-command-events
>> +            (append unread-command-events all-events)))))
>
> Can we consolidate the two "nreverse + append to u-c-e", maybe to an
> unwind-handler?

That would make sense, yes.  Premature optimization there.  (Moving the
mouse during xterm-sync does cause "a lot" of input, but it's nowhere
near enough to warrant this microoptimization).

> Also, I have the impression that we should *prepend* rather than append
> (in practice u-c-e should be nil at that point so it likely doesn't
> matter, tho).

You're right.  There are two cases, but prepending is the right thing to
do in both of them :-)

> Oh, and `(xterm-sync TERMINAL)` sounds like a very generic
> functionality, whereas the code is much more specialized and presumes
> we've send a specific escape sequence.

Is it specialized? It ensures that commands sent before the function
call affect input received after the function call. The precise escape
sequence (which is sent from within xterm-sync, not before) doesn't
matter, we just need something that will trigger a response from the
terminal.

>=C2=A0I'd use a longer name that makes it more clear what it's doing:
> "xterm-sync" says what it's for but not what it really does.

I agree; this function isn't generally useful, because there is no way
to actually do what it tries to do in all cases.  It's good enough to
prevent mouse events from showing up in the usual case (a single xterm,
no fake input from timers, no silly users hitting ESC [ ? c just for fun
just before xterm-sync runs), but that's about it.

>> @@ -544,8 +548,10 @@ turn-off-xterm-mouse-tracking-on-terminal
>>      ;; to send it too few times (or to fail to let xterm-mouse events
>>      ;; pass by untranslated).
>>      (condition-case err
>> -        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
>> -                                 terminal)
>> +        (progn
>> +          (send-string-to-terminal xterm-mouse-tracking-disable-sequenc=
e
>> +                                   terminal)
>> +          (xterm-sync terminal))
>>        ;; FIXME: This should use a dedicated error signal.
>>        (error (if (equal (cadr err) "Terminal is currently suspended")
>>                   nil
>
> Do we need the `xterm-sync` in all cases?
> IIUC we need it when we "leave" a terminal, but not when we merely turn
> the mode off.

I'm not sure.  Do we care about:

(progn
 (xterm-mouse-mode 0)
 (discard-input)
 (read-event))

producing extra text (and returning 27)?

Thanks again for the suggestions.

Here's the current version of the patch.  I tried doing something about
suspending ttys, too, but calling (suspend-tty) currently aborts for me
on an xterm.

From 72ca13cb048a0fb328b6ff05d890759f3ab99ed4 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@HIDDEN>
Subject: [PATCH 1/2] Fix throw-without-catch on slow xterms (bug#78899)

* lisp/term/xterm.el (xterm--query-name-and-version): Don't throw if
the 'catch' has gone out of scope.
---
 lisp/term/xterm.el | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 4f23a909b69..73dc15b1c25 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -908,14 +908,17 @@ xterm--query-name-and-version
   "Get the terminal name and version string (XTVERSION)."
   ;; Reduce query timeout time. The default value causes a noticeable
   ;; startup delay on terminals that ignore the query.
-  (let ((xterm-query-timeout 0.1))
+  (let ((too-late nil)
+        (xterm-query-timeout 0.1))
     (catch 'result
       (xterm--query
        "\e[>0q"
        `(("\eP>|" . ,(lambda ()
                        ;; The reply should be: \e P > | STRING \e \\
                        (let ((str (xterm--read-string ?\e ?\\)))
-                         (throw 'result str))))))
+                         (unless too-late
+                           (throw 'result str)))))))
+      (setq too-late t)
       nil)))
=20
 (defun xterm--push-map (map basemap)
--=20
2.50.0

From 4335c11c174742e1c162c8eb1f37acd1cb29b65e Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@HIDDEN>
Subject: [PATCH 2/2] Avoid unhandled mouse events on slow xterms (bug#78899=
)

* lisp/xt-mouse.el (turn-on-xterm-mouse-tracking-on-terminal):
Register 'kill-emacs' hook function.
(xterm-mouse--sync): New function.
(turn-off-xterm-mouse-tracking-on-terminal): Call
'xterm-mouse--sync' when disabling mouse tracking.
---
 lisp/xt-mouse.el | 53 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)

diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 89f9bbab608..057ed7e18e8 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -528,10 +528,57 @@ turn-on-xterm-mouse-tracking-on-terminal
                    (signal (car err) (cdr err)))))
         (push enable (terminal-parameter nil 'tty-mode-set-strings))
         (push disable (terminal-parameter nil 'tty-mode-reset-strings))
+        (add-hook 'kill-emacs-hook
+                  (lambda ()
+                    (turn-off-xterm-mouse-tracking-on-terminal terminal)))
         (set-terminal-parameter terminal 'xterm-mouse-mode t)
         (set-terminal-parameter terminal 'xterm-mouse-utf-8
                                 xterm-mouse-utf-8)))))
=20
+(declare-function xterm--read-string "xterm" (term1 &optional term2))
+
+(defun xterm-mouse--sync (terminal &optional timeout)
+  "Ensure that the TERMINAL is in a synchronized state, but obey TIMEOUT.
+
+When the sequence to disable mouse tracking has been sent and this
+function returns successfully, no further mouse events should be
+produced."
+  ;; This function tries very hard to handle all events that do not belong
+  ;; to the escape sequence we are looking for.
+  (setq timeout (or timeout 2.0))
+  (let ((i 0)
+        (skip (length unread-command-events))
+        events all-events)
+    ;; request Primary DA from terminal
+    (send-string-to-terminal "\e[0c" terminal)
+    ;; build two lists: ALL-EVENTS contains all events, while EVENTS
+    ;; associates character events (only) to their index in ALL-EVENTS.
+    ;; We filter out the expected escape sequence ("\e[?") from the
+    ;; ALL-EVENTS list.
+    (unwind-protect
+        (with-timeout (timeout nil)
+          (while (not
+                  (pcase events
+                    (`((?? . ,i0)
+                       (?\[ . ,i1)
+                       (?\e . ,i2) . ,_)
+                     (when (> i2 skip)
+                       (pop (nthcdr (- i i2) all-events))
+                       (pop (nthcdr (- i i1) all-events))
+                       (pop (nthcdr (- i i0) all-events))
+                       t))))
+            (let ((event (read-event)))
+              (push event all-events)
+              (incf i)
+              (when (characterp event)
+                (push (cons event i) events))))
+          ;; read the rest of the response
+          (xterm--read-string ?c))
+      ;; replay events that preceded or occurred within the escape
+      ;; sequence.
+      (setq unread-command-events
+            (append (nreverse all-events) unread-command-events)))))
+
 (defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
   "Disable xterm mouse tracking on TERMINAL."
   ;; Only send the disable command to those terminals to which we've alrea=
dy
@@ -544,8 +591,10 @@ turn-off-xterm-mouse-tracking-on-terminal
     ;; to send it too few times (or to fail to let xterm-mouse events
     ;; pass by untranslated).
     (condition-case err
-        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
-                                 terminal)
+        (progn
+          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
+                                   terminal)
+          (xterm-mouse--sync terminal))
       ;; FIXME: This should use a dedicated error signal.
       (error (if (equal (cadr err) "Terminal is currently suspended")
                  nil
--=20
2.50.0






Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 1 Jul 2025 22:09:33 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 01 18:09:32 2025
Received: from localhost ([127.0.0.1]:59303 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uWjAS-0007CC-1e
	for submit <at> debbugs.gnu.org; Tue, 01 Jul 2025 18:09:32 -0400
Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]:21017)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <monnier@HIDDEN>)
 id 1uWjAP-0007B1-0w
 for 78899 <at> debbugs.gnu.org; Tue, 01 Jul 2025 18:09:29 -0400
Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1])
 by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id E48E8809CD;
 Tue,  1 Jul 2025 18:09:22 -0400 (EDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca;
 s=mail; t=1751407761;
 bh=Orjbi3O9qiABlDsXtbqRuM1PyMYXnyyTI/ZgxOgT8eA=;
 h=From:To:Cc:Subject:In-Reply-To:References:Date:From;
 b=iIuFAnPM3AbR9v+CHZBK+BjvLcXw69LEHjvLZhCy0o5dWdRvwCu4MD6mOHjEoGZG2
 m+OqWEdhc0vI23IgmrDkEMc6d4ijqBFjOjutbAczLrNLlequISE29MadOzAOMKXSQ6
 F7UCcyyispOd7Kq5WMIJ8nLOLolMnetgthDxxxZMcf58VB/1T+teKLTnDg9RBPrJV4
 UlAX7/e/HzVNGZrdsloy4WMh22CuGpA014OcgUeyVDlLI6VlTtNAR7jal8EWtiGez2
 ziLJzsQgKsa43JeDCeaxIhkWqsnJvCoTD73MvUx33/3PVKsUhpJPuYFchMzRTzjF1V
 kdB13Hsbg03AQ==
Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1])
 by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id DF37180916;
 Tue,  1 Jul 2025 18:09:21 -0400 (EDT)
Received: from alfajor (modemcable005.21-80-70.mc.videotron.ca [70.80.21.5])
 by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id B1FCD1208E1;
 Tue,  1 Jul 2025 18:09:21 -0400 (EDT)
From: Stefan Monnier <monnier@HIDDEN>
To: Pip Cet <pipcet@HIDDEN>
Subject: Re: bug#78899: 30.1; garbage inserted in the terminal buffer when
 quitting Emacs
In-Reply-To: <87ecv0yhgy.fsf@HIDDEN>
Message-ID: <jwvcyaj60xi.fsf-monnier+emacs@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN>
Date: Tue, 01 Jul 2025 18:09:21 -0400
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain
X-SPAM-INFO: Spam detection results:  0
 ALL_TRUSTED                -1 Passed through trusted hosts only via SMTP
 AWL -0.166 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DKIM_SIGNED               0.1 Message has a DKIM or DK signature,
 not necessarily valid
 DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature
 DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's
 domain
 DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from
 domain
X-SPAM-LEVEL: 
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, Eli Zaretskii <eliz@HIDDEN>, vincent@HIDDEN,
 78899 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> * lisp/term/xterm.el (xterm--query-name-and-version): Accept
> 'callback' argument.  Call it.
> (xterm--init): Handle asynchronous terminal id responses.

Hmm... you may want to check the code history, because I have a vague
recollection that we had something along these lines at some point and
it bumped into other problems, probably when ELisp code runs between
`xterm--query-name-and-version` and its callback, and sends other things
to the terminal or reads from the terminal.

Maybe I misremember, of course.

> +(defun xterm-sync (terminal &optional timeout)
> +  "Ensure that the TERMINAL is in a synchronized state, but obey TIMEOUT."
> +  ;; This function tries very hard to handle all events that do not belong
> +  ;; to the escape sequence we are looking for.  It's usually called only
> +  ;; when Emacs quits, so this might be overkill.
> +  (setq timeout (or timeout 2.0))
> +  (let ((i 0)
> +        events all-events)
> +    ;; request Primary DA from terminal
> +    (send-string-to-terminal "\e[0c" terminal)
> +    ;; build two lists: ALL-EVENTS contains all events, while EVENTS
> +    ;; associates character events (only) to their index in ALL-EVENTS.
> +    ;; We filter out the expected escape sequence ("\e[?") from the
> +    ;; ALL-EVENTS list.
> +    (with-timeout (timeout
> +                   (setq unread-command-events
> +                         (append unread-command-events
> +                                 (nreverse all-events))))
> +      (while (not
> +              (pcase events
> +                (`((?? . ,i0)
> +                   (?\[ . ,i1)
> +                   (?\e . ,i2) . ,_)
> +                 (setq all-events (nreverse all-events))
> +                 (pop (nthcdr i0 all-events))
> +                 (pop (nthcdr i1 all-events))
> +                 (pop (nthcdr i2 all-events))
> +                 t)))
> +        (let ((event (read-event)))
> +          (push event all-events)
> +          (when (characterp event)
> +            (push (cons event i) events))
> +          (incf i)))
> +      ;; read the rest of the response
> +      (xterm--read-string ?c)
> +      ;; replay events that preceded or occurred within the escape
> +      ;; sequence.
> +      (setq unread-command-events
> +            (append unread-command-events all-events)))))

Can we consolidate the two "nreverse + append to u-c-e", maybe to an
unwind-handler?
Also, I have the impression that we should *prepend* rather than append
(in practice u-c-e should be nil at that point so it likely doesn't
matter, tho).

Oh, and `(xterm-sync TERMINAL)` sounds like a very generic
functionality, whereas the code is much more specialized and presumes
we've send a specific escape sequence.  I'd use a longer name that makes
it more clear what it's doing: "xterm-sync" says what it's for but not
what it really does.

> @@ -544,8 +548,10 @@ turn-off-xterm-mouse-tracking-on-terminal
>      ;; to send it too few times (or to fail to let xterm-mouse events
>      ;; pass by untranslated).
>      (condition-case err
> -        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> -                                 terminal)
> +        (progn
> +          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
> +                                   terminal)
> +          (xterm-sync terminal))
>        ;; FIXME: This should use a dedicated error signal.
>        (error (if (equal (cadr err) "Terminal is currently suspended")
>                   nil

Do we need the `xterm-sync` in all cases?
IIUC we need it when we "leave" a terminal, but not when we merely turn
the mode off.


        Stefan





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 1 Jul 2025 11:53:50 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 01 07:53:49 2025
Received: from localhost ([127.0.0.1]:55430 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uWZYY-0001V2-Ce
	for submit <at> debbugs.gnu.org; Tue, 01 Jul 2025 07:53:48 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:55656)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1uWZYT-0001TS-GB
 for 78899 <at> debbugs.gnu.org; Tue, 01 Jul 2025 07:53:42 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1uWZYL-0006DN-Ei; Tue, 01 Jul 2025 07:53:33 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=RNd9fgNUzbcH3P6UaBMAZKstLp/Etn5cEqUq0XcPBoE=; b=cJLmVs3ERi1o
 JkxCHps8vLvCx+M34Q20qX8p+pGdq/E2/nRUnRLWWQ+oNZg0eO7a0bG6l4G7MPvYtzr76iFLepJeP
 fHwLlfUOc5JhoYBkNPjCMBemN4OISnbG0u02c1Lcp4EvzZzLWTbsNjxJtYxNJWWAlgmeTbAOB/u3+
 f2cNTaftH40xQOgzryKLnjiJEAAsCESK6dUz6aY0EEt2ofIDULv3X4c2xLHl2ZRqrG5KAdFCXIoNh
 01NaR2g4CPjAmNbGSoCQ4hkGBLRIFygaTG+93jR3DIbZDY40mr3wycAX9sH3+u8lGzxZTiel1jtAg
 V08MA+BCU4ArVU3ksQGZnA==;
Date: Tue, 01 Jul 2025 14:53:28 +0300
Message-Id: <86h5zw2klj.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Pip Cet <pipcet@HIDDEN>, Jared Finder <jared@HIDDEN>,
 Stefan Monnier <monnier@HIDDEN>
In-Reply-To: <87ecv0yhgy.fsf@HIDDEN> (message from Pip Cet on Mon, 30
 Jun 2025 22:47:45 +0000)
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
 <87ecv0yhgy.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, 78899 <at> debbugs.gnu.org, vincent@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Date: Mon, 30 Jun 2025 22:47:45 +0000
> From: Pip Cet <pipcet@HIDDEN>
> Cc: vincent@HIDDEN, luangruo@HIDDEN, 78899 <at> debbugs.gnu.org
> 
> "Eli Zaretskii" <eliz@HIDDEN> writes:
> 
> >> Date: Thu, 26 Jun 2025 11:37:12 +0000
> >> From: Pip Cet <pipcet@HIDDEN>
> >> Cc: Vincent Lefevre <vincent@HIDDEN>, Po Lu <luangruo@HIDDEN>, 78899 <at> debbugs.gnu.org
> >>
> >> We could possibly fix this by asking for another report from xterm upon
> >> termination and waiting for the response?
> >
> > Yes, I think something like that would make sense.
> 
> It turns out that the request-response cycle to ensure the remote xterm
> has caught up to our output is a little tricky: we don't want to use the
> command loop like xterm--query does, because we're usually called from
> within kill-emacs and won't return to the command loop.  We also can't
> do it in C, because the code to read from a terminal without blocking is
> highly system-dependent.
> 
> So that leaves read-event.  I went to some trouble to collect all events
> in a list, removing only those that constitute our response escape
> sequence and pushing the rest to unread-command-events; I believe that's
> the right thing to do because we might want to auto-disable
> xterm-mouse-mode when we detect a slow terminal one day, as the old code
> effectively did.  However, maybe the low-level key thing would be a
> better alternative and allow restricting input to one terminal only?
> 
> Here are the two patches; I'm aware of a whitespace issue, and we need
> to decide on a sensible timeout for xterm-sync: I used 2.0 seconds
> because I think the most common scenario for slow xterm connections is a
> Tor connection, and Tor appears to add up to about 1.2 seconds of
> (round-trip) latency.

Thanks.  Jared and Stefan, any comments?




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 30 Jun 2025 22:48:05 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jun 30 18:48:04 2025
Received: from localhost ([127.0.0.1]:51464 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uWNIA-0004B9-2R
	for submit <at> debbugs.gnu.org; Mon, 30 Jun 2025 18:48:04 -0400
Received: from mail-4316.protonmail.ch ([185.70.43.16]:25601)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <pipcet@HIDDEN>)
 id 1uWNI6-00049b-CH
 for 78899 <at> debbugs.gnu.org; Mon, 30 Jun 2025 18:47:59 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;
 s=protonmail3; t=1751323670; x=1751582870;
 bh=hI2INEjQLhmSHEtH4PrU2sJMyhUgVu8MKpkUBocgOhc=;
 h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:
 Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:
 Message-ID:BIMI-Selector;
 b=pmFnQFsKrwY1n+Z2GmytME6ZvQLyS7qTz1UO/qnqy0SWmzKOTUVntXRvOcgbMIvq5
 phTyWHA3GWLldzGD/NSKH8A/k7wj2r6lHZmDD4+U9nBqpPAC1kmXxPlmE67dtDWnSG
 Mz+Fa2LIaDDkV1Wb2cqT5tL1P6P5uNQd+lrPBE0WkOr8oDzr0MRKDGPvdbVEXxPTBX
 C2cN4Hcl7EmvnGIw31W9LBO5XdquhNbIcU3k/VpuVGGHUgI5JBUfSqeMiQAHx2hTaV
 ANAh60RY8DQx36Bi7rJW6xTfy2CTOfFOS+EPjU7FoEhseNbk9FaYy9tB2qlERiVQbz
 DaHQOPx8Vd7EA==
Date: Mon, 30 Jun 2025 22:47:45 +0000
To: Eli Zaretskii <eliz@HIDDEN>
From: Pip Cet <pipcet@HIDDEN>
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
Message-ID: <87ecv0yhgy.fsf@HIDDEN>
In-Reply-To: <861pr6d6k0.fsf@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN> <861pr6d6k0.fsf@HIDDEN>
Feedback-ID: 112775352:user:proton
X-Pm-Message-ID: 39b6aa2ec5afd6e6700fcde7e4d94fe879589ed3
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.2 (/)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, 78899 <at> debbugs.gnu.org, vincent@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -0.8 (/)

"Eli Zaretskii" <eliz@HIDDEN> writes:

>> Date: Thu, 26 Jun 2025 11:37:12 +0000
>> From: Pip Cet <pipcet@HIDDEN>
>> Cc: Vincent Lefevre <vincent@HIDDEN>, Po Lu <luangruo@HIDDEN>, 78=
899 <at> debbugs.gnu.org
>>
>> We could possibly fix this by asking for another report from xterm upon
>> termination and waiting for the response?
>
> Yes, I think something like that would make sense.

It turns out that the request-response cycle to ensure the remote xterm
has caught up to our output is a little tricky: we don't want to use the
command loop like xterm--query does, because we're usually called from
within kill-emacs and won't return to the command loop.  We also can't
do it in C, because the code to read from a terminal without blocking is
highly system-dependent.

So that leaves read-event.  I went to some trouble to collect all events
in a list, removing only those that constitute our response escape
sequence and pushing the rest to unread-command-events; I believe that's
the right thing to do because we might want to auto-disable
xterm-mouse-mode when we detect a slow terminal one day, as the old code
effectively did.  However, maybe the low-level key thing would be a
better alternative and allow restricting input to one terminal only?

Here are the two patches; I'm aware of a whitespace issue, and we need
to decide on a sensible timeout for xterm-sync: I used 2.0 seconds
because I think the most common scenario for slow xterm connections is a
Tor connection, and Tor appears to add up to about 1.2 seconds of
(round-trip) latency.

From 4cc6d43fd3f105b15f8079cf647c83bb511db339 Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@HIDDEN>
Subject: [PATCH 1/2] Make xterm--query-name-and-version use a callback patt=
ern
 (bug#78899)

The previous code would throw without a containing catch on slow
terminal connections.

* lisp/term/xterm.el (xterm--query-name-and-version): Accept
'callback' argument.  Call it.
(xterm--init): Handle asynchronous terminal id responses.
---
 lisp/term/xterm.el | 44 +++++++++++++++++++++++---------------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 4f23a909b69..4fe27775364 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -904,19 +904,19 @@ xterm--query
               (push (aref (car handler) (setq i (1- i)))
                     unread-command-events))))))))
=20
-(defun xterm--query-name-and-version ()
-  "Get the terminal name and version string (XTVERSION)."
+(defun xterm--query-name-and-version (callback)
+  "Get the terminal name and version string (XTVERSION).
+CALLBACK is called asynchronously when a response is received."
   ;; Reduce query timeout time. The default value causes a noticeable
   ;; startup delay on terminals that ignore the query.
-  (let ((xterm-query-timeout 0.1))
-    (catch 'result
-      (xterm--query
-       "\e[>0q"
-       `(("\eP>|" . ,(lambda ()
-                       ;; The reply should be: \e P > | STRING \e \\
-                       (let ((str (xterm--read-string ?\e ?\\)))
-                         (throw 'result str))))))
-      nil)))
+  (let ((xterm-query-timeout nil))
+    (xterm--query
+     "\e[>0q"
+     `(("\eP>|" . ,(lambda ()
+                     ;; The reply should be: \e P > | STRING \e \\
+                     (let ((str (xterm--read-string ?\e ?\\)))
+                       (funcall callback str))))))
+    nil))
=20
 (defun xterm--push-map (map basemap)
   ;; Use inheritance to let the main keymaps override those defaults.
@@ -965,16 +965,18 @@ xterm--init
=20
   (when xterm-set-window-title
     (xterm--init-frame-title))
-  (when (and (not xterm-mouse-mode-called)
-             ;; Only automatically enable xterm mouse on terminals
-             ;; confirmed to still support all critical editing
-             ;; workflows (bug#74833).
-             (or (string-match-p xterm--auto-xt-mouse-allowed-types
-                                 (tty-type (selected-frame)))
-                 (and-let* ((name-and-version (xterm--query-name-and-versi=
on)))
-                   (string-match-p xterm--auto-xt-mouse-allowed-names
-                                   name-and-version))))
-    (xterm-mouse-mode 1))
+  (when (not xterm-mouse-mode-called)
+    ;; Only automatically enable xterm mouse on terminals
+    ;; confirmed to still support all critical editing
+    ;; workflows (bug#74833).
+    (if (string-match-p xterm--auto-xt-mouse-allowed-types
+                        (tty-type (selected-frame)))
+        (xterm-mouse-mode 1)
+      (xterm--query-name-and-version
+       (lambda (name-and-version)
+         (when (string-match-p xterm--auto-xt-mouse-allowed-names
+                               name-and-version)
+           (xterm-mouse-mode 1))))))
   ;; Unconditionally enable bracketed paste mode: terminals that don't
   ;; support it just ignore the sequence.
   (xterm--init-bracketed-paste-mode)
--=20
2.50.0

From 8d9bc5b59ba34252b9cefc23fe673e6345a3e6fd Mon Sep 17 00:00:00 2001
From: Pip Cet <pipcet@HIDDEN>
Subject: [PATCH 2/2] Don't let xterm mouse events arrive after we quit
 (bug#78899)

* lisp/term/xterm.el (xterm-sync): New function.
* lisp/xt-mouse.el (turn-on-xterm-mouse-tracking-on-terminal):
Register 'kill-emacs' hook function.
(xterm-sync): Declare.
(turn-off-xterm-mouse-tracking-on-terminal): Call 'xterm-sync' before
we stop processing mouse events.
---
 lisp/term/xterm.el | 40 ++++++++++++++++++++++++++++++++++++++++
 lisp/xt-mouse.el   | 10 ++++++++--
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 4fe27775364..cbc8a2b8398 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -918,6 +918,46 @@ xterm--query-name-and-version
                        (funcall callback str))))))
     nil))
=20
+(defun xterm-sync (terminal &optional timeout)
+  "Ensure that the TERMINAL is in a synchronized state, but obey TIMEOUT."
+  ;; This function tries very hard to handle all events that do not belong
+  ;; to the escape sequence we are looking for.  It's usually called only
+  ;; when Emacs quits, so this might be overkill.
+  (setq timeout (or timeout 2.0))
+  (let ((i 0)
+        events all-events)
+    ;; request Primary DA from terminal
+    (send-string-to-terminal "\e[0c" terminal)
+    ;; build two lists: ALL-EVENTS contains all events, while EVENTS
+    ;; associates character events (only) to their index in ALL-EVENTS.
+    ;; We filter out the expected escape sequence ("\e[?") from the
+    ;; ALL-EVENTS list.
+    (with-timeout (timeout
+                   (setq unread-command-events
+                         (append unread-command-events
+                                 (nreverse all-events))))
+      (while (not
+              (pcase events
+                (`((?? . ,i0)
+                   (?\[ . ,i1)
+                   (?\e . ,i2) . ,_)
+                 (setq all-events (nreverse all-events))
+                 (pop (nthcdr i0 all-events))
+                 (pop (nthcdr i1 all-events))
+                 (pop (nthcdr i2 all-events))
+                 t)))
+        (let ((event (read-event)))
+          (push event all-events)
+          (when (characterp event)
+            (push (cons event i) events))
+          (incf i)))
+      ;; read the rest of the response
+      (xterm--read-string ?c)
+      ;; replay events that preceded or occurred within the escape
+      ;; sequence.
+      (setq unread-command-events
+            (append unread-command-events all-events)))))
+
 (defun xterm--push-map (map basemap)
   ;; Use inheritance to let the main keymaps override those defaults.
   ;; This way we don't override terminfo-derived settings or settings
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 89f9bbab608..884ae3ab274 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -528,10 +528,14 @@ turn-on-xterm-mouse-tracking-on-terminal
                    (signal (car err) (cdr err)))))
         (push enable (terminal-parameter nil 'tty-mode-set-strings))
         (push disable (terminal-parameter nil 'tty-mode-reset-strings))
+        (add-hook 'kill-emacs-hook (lambda ()
+                                     (turn-off-xterm-mouse-tracking-on-ter=
minal terminal)))
         (set-terminal-parameter terminal 'xterm-mouse-mode t)
         (set-terminal-parameter terminal 'xterm-mouse-utf-8
                                 xterm-mouse-utf-8)))))
=20
+(declare-function xterm-sync "xterm" (terminal &optional timeout))
+
 (defun turn-off-xterm-mouse-tracking-on-terminal (terminal)
   "Disable xterm mouse tracking on TERMINAL."
   ;; Only send the disable command to those terminals to which we've alrea=
dy
@@ -544,8 +548,10 @@ turn-off-xterm-mouse-tracking-on-terminal
     ;; to send it too few times (or to fail to let xterm-mouse events
     ;; pass by untranslated).
     (condition-case err
-        (send-string-to-terminal xterm-mouse-tracking-disable-sequence
-                                 terminal)
+        (progn
+          (send-string-to-terminal xterm-mouse-tracking-disable-sequence
+                                   terminal)
+          (xterm-sync terminal))
       ;; FIXME: This should use a dedicated error signal.
       (error (if (equal (cadr err) "Terminal is currently suspended")
                  nil
--=20
2.50.0





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 26 Jun 2025 12:35:41 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 26 08:35:41 2025
Received: from localhost ([127.0.0.1]:49126 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uUlpN-0002V2-2E
	for submit <at> debbugs.gnu.org; Thu, 26 Jun 2025 08:35:41 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:34586)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1uUlpJ-0002UP-6i
 for 78899 <at> debbugs.gnu.org; Thu, 26 Jun 2025 08:35:38 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1uUlpC-000818-6u; Thu, 26 Jun 2025 08:35:30 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=gIf7H6sX7aYtScMTfO/+O81S7Td1KGVv6SpvT0XR1JY=; b=DI15iDuFmMS6
 y7CAFZgxJvigbk931sZwHii6ho7TnNrH9dDKVU1qFGF7DJGq9lMuL3N6QX5vO0zNEKeGayO5NhEY2
 /TrgVBrQMOIj4bPEnEhNxV4RDuST82qy5oCXpv7KosyXyeCMtwYsSpoXKJNgF0FgcneLe0A1wdeD/
 nRkt+RQE0B75ZVZPbChim1ObahHyrhCNA9xkPtJ5k3ZT73RJKbRUE+uWRxIxJJbYX/KWinAV0PXt3
 15mA6YQNO2RUxx2Ig2zbyr6tz6ESacwuLNE1oQsakt914Dj963FESY4N1EvEuDijeCVJb4iiUWd6i
 TvDNACoDmPBu16IBzsa06g==;
Date: Thu, 26 Jun 2025 15:35:27 +0300
Message-Id: <861pr6d6k0.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Pip Cet <pipcet@HIDDEN>
In-Reply-To: <87v7oi4tul.fsf@HIDDEN> (message from Pip Cet on Thu, 26
 Jun 2025 11:37:12 +0000)
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
 <87v7oi4tul.fsf@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: luangruo@HIDDEN, 78899 <at> debbugs.gnu.org, vincent@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Date: Thu, 26 Jun 2025 11:37:12 +0000
> From: Pip Cet <pipcet@HIDDEN>
> Cc: Vincent Lefevre <vincent@HIDDEN>, Po Lu <luangruo@HIDDEN>, 78899 <at> debbugs.gnu.org
> 
> We could possibly fix this by asking for another report from xterm upon
> termination and waiting for the response?

Yes, I think something like that would make sense.




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 26 Jun 2025 11:37:28 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 26 07:37:27 2025
Received: from localhost ([127.0.0.1]:48806 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uUkv1-0007ep-Fe
	for submit <at> debbugs.gnu.org; Thu, 26 Jun 2025 07:37:27 -0400
Received: from mail-4322.protonmail.ch ([185.70.43.22]:58033)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <pipcet@HIDDEN>)
 id 1uUkuy-0007eH-4C
 for 78899 <at> debbugs.gnu.org; Thu, 26 Jun 2025 07:37:25 -0400
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;
 s=protonmail3; t=1750937836; x=1751197036;
 bh=2kjYKSGz5qsAc5JmWw0MXHdE7LfB+A68A5QNPPJyiyE=;
 h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References:
 Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:
 Message-ID:BIMI-Selector;
 b=e1ZDthurQvdp4Pn5XNcyoJ8uzziQNuJPW/GCR3mlCVOF1Z5P3x6EpYavPHNQK95dT
 w3EjNa12gmgXJYkw7CPLZ1YwKucx9VrXbBJW5ZvwRcUSiI51MIxg5TzdTjyEY4Dc+Y
 YOWy4+Ij5Cth5m6zK4evgIMx2oSAun+49QG5EqCA5FykSo2xBgNaek39oOHPzhAaen
 5sDWa0wy/fIVRyFFGWVNBZnR0+LfKMLIGfIGcvZiRoJYphEqOViOY3+3azKToA1Xad
 E0fSfDtiWLgEo7XGQgswScNFAcpMEyxD0fwjcHBrP3NgT8fvNC9pryAdK9xlkJvZ93
 LprtvdIlLVlyw==
Date: Thu, 26 Jun 2025 11:37:12 +0000
To: Eli Zaretskii <eliz@HIDDEN>
From: Pip Cet <pipcet@HIDDEN>
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
Message-ID: <87v7oi4tul.fsf@HIDDEN>
In-Reply-To: <86ldpfc9fe.fsf@HIDDEN>
References: <20250626003758.GG2809@HIDDEN> <86ldpfc9fe.fsf@HIDDEN>
Feedback-ID: 112775352:user:proton
X-Pm-Message-ID: 9fd2061cc33f3eb4820af100ffb965083cb74b6d
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 78899
Cc: Po Lu <luangruo@HIDDEN>, 78899 <at> debbugs.gnu.org,
 Vincent Lefevre <vincent@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

"Eli Zaretskii" <eliz@HIDDEN> writes:

>> Date: Thu, 26 Jun 2025 02:37:58 +0200
>> From: Vincent Lefevre <vincent@HIDDEN>
>>
>> I ran "emacs -nw some_file" on my Android phone via ssh in xterm,
>> where emacs is provided by Termux.
>>
>> Just after I quit Emacs with C-x C-c, I got the following in the
>> terminal buffer, which became input at the shell prompt:
>>
>> ^[[<35;42;25M35;40;24M35;37;24M35;42;25M35;33;23M
>>
>> I think that this was the first time this occurred.
>>
>> Note that there were no issues with the network (this is on the
>> local network at home).
>
> That could be some kind of command we send to the terminal, which the
> terminal doesn't support?
>
> Po Lu, any ideas?

Those are mouse movements reported by xterm.  I can reproduce this by
using a slow connection, enabling xterm-mouse-mode, quitting Emacs, and
moving the mouse while that process is being sent.

I think what happens is that we send the escape sequence to disable
those just before exiting, without waiting for that escape sequence to
be processed by the terminal, so xterm keeps sending them to the next
application for a while.

Note that xterm--query-name-and-version fails on slow connections, too:
the timeout is set to 0.1 s, and if we don't get a response in that time,
we get an asynchronous throw to a tag that no longer has a catch.  This
produces the error message:

No catch for tag: result, "XTerm(400)"

IIUC, the xterm--query-name-and-version bug hides the other bug:
usually, if you have a slow connection, xterm mouse mode won't be
enabled automatically because we fail to recognize the terminal.  If you
have a fast connection, such as a local display, the window for mouse
movements to be reported is small.

We could possibly fix this by asking for another report from xterm upon
termination and waiting for the response?

Pip





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at 78899 <at> debbugs.gnu.org:


Received: (at 78899) by debbugs.gnu.org; 26 Jun 2025 06:18:57 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jun 26 02:18:57 2025
Received: from localhost ([127.0.0.1]:47078 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uUfwm-0001VC-K0
	for submit <at> debbugs.gnu.org; Thu, 26 Jun 2025 02:18:57 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10]:60856)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1uUfwj-0001UG-QK
 for 78899 <at> debbugs.gnu.org; Thu, 26 Jun 2025 02:18:54 -0400
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1uUfwd-0005x5-L9; Thu, 26 Jun 2025 02:18:47 -0400
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date:
 mime-version; bh=vTi0LpS7O4X1gwXq2RLw1TEcFuot2Pi1Iu/jPe01uU8=; b=IRMRiHBKbnud
 IXud9mSW1KiLaKjs4Ud3jsih6nxs2GkAvWnDpOYSH7BXqZu3o6hFszITJKxOOiM3LtZZl6hpcI4Fo
 9NfvjgIfvbxCTcdPoYRPRXypzbsHsmO1bXZ4suWVJKRRi5o0G72U1+cRQKE/cOAMBGgbr8f/WA/Fe
 S3NH+mo8llBTIu8nD9TSb2iSwj+kMg7ztx/iXPJ8GsQSgIFrSzW8bXdYwfLTCQT46u61qeG37owWj
 HNZNEeEE1kuKDupbu9qAfrBMxuXuy/J/nf9WSQ1wK9EmwsZumvhAMYqxNUU4uj4F8NCmJHyT+xhy2
 0x5q6vDz4n2IgdJnktoyVg==;
Date: Thu, 26 Jun 2025 09:18:45 +0300
Message-Id: <86ldpfc9fe.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: Vincent Lefevre <vincent@HIDDEN>, Po Lu <luangruo@HIDDEN>
In-Reply-To: <20250626003758.GG2809@HIDDEN> (message from Vincent
 Lefevre on Thu, 26 Jun 2025 02:37:58 +0200)
Subject: Re: bug#78899: 30.1;
 garbage inserted in the terminal buffer when quitting Emacs
References: <20250626003758.GG2809@HIDDEN>
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 78899
Cc: 78899 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Date: Thu, 26 Jun 2025 02:37:58 +0200
> From: Vincent Lefevre <vincent@HIDDEN>
> 
> I ran "emacs -nw some_file" on my Android phone via ssh in xterm,
> where emacs is provided by Termux.
> 
> Just after I quit Emacs with C-x C-c, I got the following in the
> terminal buffer, which became input at the shell prompt:
> 
> ^[[<35;42;25M35;40;24M35;37;24M35;42;25M35;33;23M
> 
> I think that this was the first time this occurred.
> 
> Note that there were no issues with the network (this is on the
> local network at home).

That could be some kind of command we send to the terminal, which the
terminal doesn't support?

Po Lu, any ideas?




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 26 Jun 2025 00:38:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jun 25 20:38:25 2025
Received: from localhost ([127.0.0.1]:41568 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1uUadE-00019t-G0
	for submit <at> debbugs.gnu.org; Wed, 25 Jun 2025 20:38:25 -0400
Received: from lists.gnu.org ([2001:470:142::17]:33878)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <vincent@HIDDEN>)
 id 1uUadB-00019c-5b
 for submit <at> debbugs.gnu.org; Wed, 25 Jun 2025 20:38:21 -0400
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <vincent@HIDDEN>)
 id 1uUad4-0007A1-Uk
 for bug-gnu-emacs@HIDDEN; Wed, 25 Jun 2025 20:38:15 -0400
Received: from joooj.vinc17.net ([155.133.131.76])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <vincent@HIDDEN>)
 id 1uUad2-0004KM-NQ
 for bug-gnu-emacs@HIDDEN; Wed, 25 Jun 2025 20:38:14 -0400
Received: from smtp-qaa.vinc17.net (135.197.67.86.rev.sfr.net [86.67.197.135])
 by joooj.vinc17.net (Postfix) with ESMTPSA id 9AF232F4;
 Thu, 26 Jun 2025 02:37:58 +0200 (CEST)
Received: by qaa.vinc17.org (Postfix, from userid 1000)
 id 5AD5FCA0431; Thu, 26 Jun 2025 02:37:58 +0200 (CEST)
Date: Thu, 26 Jun 2025 02:37:58 +0200
From: Vincent Lefevre <vincent@HIDDEN>
To: bug-gnu-emacs@HIDDEN
Subject: 30.1; garbage inserted in the terminal buffer when quitting Emacs
Message-ID: <20250626003758.GG2809@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
X-Mailer-Info: https://www.vinc17.net/mutt/
User-Agent: Mutt/2.2.13+86 (bb2064ae) vl-169878 (2025-02-08)
Received-SPF: pass client-ip=155.133.131.76; envelope-from=vincent@HIDDEN;
 helo=joooj.vinc17.net
X-Spam_score_int: -18
X-Spam_score: -1.9
X-Spam_bar: -
X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9,
 RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001,
 SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: -0.0 (/)
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

I ran "emacs -nw some_file" on my Android phone via ssh in xterm,
where emacs is provided by Termux.

Just after I quit Emacs with C-x C-c, I got the following in the
terminal buffer, which became input at the shell prompt:

^[[<35;42;25M35;40;24M35;37;24M35;42;25M35;33;23M

I think that this was the first time this occurred.

Note that there were no issues with the network (this is on the
local network at home).

In GNU Emacs 30.1 (build 1, aarch64-unknown-linux-android) of 2025-06-18
 built on localhost
Configured using:
 'configure --disable-dependency-tracking
 --prefix=/data/data/com.termux/files/usr
 --libdir=/data/data/com.termux/files/usr/lib
 --includedir=/data/data/com.termux/files/usr/include
 --sbindir=/data/data/com.termux/files/usr/bin --disable-rpath
 --disable-rpath-hack --host=aarch64-linux-android --disable-autodepend
 --with-dumping=none --with-gif=no --with-gnutls --with-jpeg=no
 --with-modules --with-pdumper=yes --with-png=no --with-tiff=no
 --with-xml2 --with-xpm=no --with-tree-sitter --without-dbus
 --without-gconf --without-gsettings --without-lcms2 --without-selinux
 --without-x emacs_cv_alternate_stack=yes emacs_cv_sanitize_address=yes
 emacs_cv_prog_cc_no_pie=no ac_cv_lib_elf_elf_begin=no
 gl_cv_func_dup2_works=no ac_cv_func_setrlimit=no --disable-nls
 --enable-shared --enable-static
 --libexecdir=/data/data/com.termux/files/usr/libexec 'CFLAGS=
 -fstack-protector-strong -Oz' 'CPPFLAGS=
 -isystem/data/data/com.termux/files/usr/include/c++/v1
 -isystem/data/data/com.termux/files/usr/include'
 'LDFLAGS=-L/data/data/com.termux/files/usr/lib
 -Wl,-rpath=/data/data/com.termux/files/usr/lib -Wl,--enable-new-dtags
 -Wl,--as-needed -Wl,-z,relro,-z,now''

Configured features:
GMP GNUTLS LIBXML2 MODULES NOTIFY INOTIFY PDUMPER SECCOMP SQLITE3
THREADS TREE_SITTER XIM ZLIB

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

Major mode: Fundamental

Minor modes in effect:
  display-time-mode: t
  xterm-mouse-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-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
  column-number-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 cl-extra help-mode tool-bar warnings icons
emacsbug message mailcap yank-media puny dired dnd dired-loaddefs rfc822
mml mml-sec password-cache epa derived epg rfc6068 epg-config gnus-util
text-property-search time-date subr-x mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047
rfc2045 ietf-drums mm-util mail-prsvr mail-utils vc-dispatcher vc-svn
term/xterm xterm byte-opt gv bytecomp byte-compile time image cus-load
cc-styles cc-align cc-engine cc-vars cc-defs regexp-opt cl-loaddefs
cl-lib xt-mouse rmc iso-transl tooltip cconv eldoc paren electric
uniquify ediff-hook vc-hooks lisp-float-type elisp-mode tabulated-list
replace newcomment text-mode lisp-mode prog-mode register page tab-bar
menu-bar rfn-eshadow isearch easymenu timer select 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 inotify
multi-tty make-network-process emacs)

-- 
Vincent Lefèvre <vincent@HIDDEN> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / Pascaline project (LIP, ENS-Lyon)




Acknowledgement sent to Vincent Lefevre <vincent@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#78899; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sat, 9 Aug 2025 12:15:01 UTC

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