GNU bug report logs -
#79513
30.1.90; selected-window and current-buffer can start out of sync for text terminal emacsclient
Previous Next
To reply to this bug, email your comments to 79513 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
app-emacs-dev <at> janestreet.com, bug-gnu-emacs <at> gnu.org:
bug#79513; Package
emacs.
(Thu, 25 Sep 2025 18:39:03 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Spencer Baugh <sbaugh <at> janestreet.com>:
New bug report received and forwarded. Copy sent to
app-emacs-dev <at> janestreet.com, bug-gnu-emacs <at> gnu.org.
(Thu, 25 Sep 2025 18:39:03 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Running emacsclient to start open a new text terminal frame, and using
--eval to change the selected window on that frame, causes
current-buffer to get out of sync with selected-window for the first key
sequence read on that frame. The key sequence will be looked up in the
keymaps for current-buffer, and afterwards the found command will be run
in the window-buffer of selected-window.
This only happens on some terminals; so far I've reproduced it inside
screen, tmux, and vterm. I think this is because other terminals emit
spurious events before the first user input, so by the time the user
provides input, current-buffer and selected-window are in sync again.
1. emacs -Q --fg-daemon=test
2. In screen, tmux, or vterm:
emacsclient -t --socket-name=test --eval '(pop-to-buffer (list-buffers-noselect))'
3. Hit q
4. Observe the error: "Buffer is read-only: #<buffer *Buffer List*>"
This is because q gets looked up in the keymap for *scratch*, which
has it bound to self-insert-command, which is then run in *Buffer List*.
5. Hit q
6. Observe the buffer list window being quit, since the second key
sequence is correctly looked up in *Buffer List*, producing quit-window.
This is the result of this hack in read_key_sequence, called by
command_loop_1:
if ((FIXNUMP (key) && XFIXNUM (key) == -2) /* wrong_kboard_jmpbuf */
/* When switching to a new tty (with a new keyboard),
read_char returns the new buffer, rather than -2
(Bug#5095). This is because `terminal-init-xterm'
calls read-char, which eats the wrong_kboard_jmpbuf
return. Any better way to fix this? -- cyd */
|| (interrupted_kboard != current_kboard))
Because of this, even though command_loop_1 calls read_key_sequence with
a "true" value for fix_current_buffer, the fix_current_buffer
conditional isn't hit in read_key_sequence, and we don't run
"Fset_buffer (XWINDOW (selected_window)->contents)" as we should.
In GNU Emacs 30.1.90 (build 57, x86_64-pc-linux-gnu, X toolkit, cairo
version 1.15.12, Xaw scroll bars) of 2025-09-23 built on
igm-qws-u22796a
Repository revision: 61402089ce10ee7d50e8923083de56571968a239
Repository branch: emacs-30
Windowing system distributor 'The X.Org Foundation', version 11.0.12011000
System Description: Rocky Linux 8.10 (Green Obsidian)
Configured using:
'configure --with-x-toolkit=lucid --without-gpm --without-gconf
--without-selinux --without-imagemagick --with-modules --with-gif=no
--with-cairo --with-rsvg --without-compress-install --with-tree-sitter
--with-native-compilation=aot
PKG_CONFIG_PATH=/usr/local/home/garnish/libtree-sitter/0.22.6-1/lib/pkgconfig/'
Configured features:
CAIRO DBUS FREETYPE GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LIBSYSTEMD
LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP
SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER X11 XDBE XIM
XINPUT2 XPM LUCID ZLIB
Important settings:
value of $LANG: en_US.UTF-8
locale-coding-system: utf-8-unix
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79513; Package
emacs.
(Tue, 21 Oct 2025 17:07:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 79513 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
Hello,
On Thu 25 Sep 2025 at 02:38pm -04, Spencer Baugh wrote:
> Running emacsclient to start open a new text terminal frame, and using
> --eval to change the selected window on that frame, causes
> current-buffer to get out of sync with selected-window for the first key
> sequence read on that frame. The key sequence will be looked up in the
> keymaps for current-buffer, and afterwards the found command will be run
> in the window-buffer of selected-window.
>
> This only happens on some terminals; so far I've reproduced it inside
> screen, tmux, and vterm. I think this is because other terminals emit
> spurious events before the first user input, so by the time the user
> provides input, current-buffer and selected-window are in sync again.
I can reproduce it with the foot terminal emulator.
> 1. emacs -Q --fg-daemon=test
> 2. In screen, tmux, or vterm:
> emacsclient -t --socket-name=test --eval '(pop-to-buffer (list-buffers-noselect))'
> 3. Hit q
> 4. Observe the error: "Buffer is read-only: #<buffer *Buffer List*>"
> This is because q gets looked up in the keymap for *scratch*, which
> has it bound to self-insert-command, which is then run in *Buffer List*.
> 5. Hit q
> 6. Observe the buffer list window being quit, since the second key
> sequence is correctly looked up in *Buffer List*, producing quit-window.
>
> This is the result of this hack in read_key_sequence, called by
> command_loop_1:
>
> if ((FIXNUMP (key) && XFIXNUM (key) == -2) /* wrong_kboard_jmpbuf */
> /* When switching to a new tty (with a new keyboard),
> read_char returns the new buffer, rather than -2
> (Bug#5095). This is because `terminal-init-xterm'
> calls read-char, which eats the wrong_kboard_jmpbuf
> return. Any better way to fix this? -- cyd */
> || (interrupted_kboard != current_kboard))
>
> Because of this, even though command_loop_1 calls read_key_sequence with
> a "true" value for fix_current_buffer, the fix_current_buffer
> conditional isn't hit in read_key_sequence, and we don't run
> "Fset_buffer (XWINDOW (selected_window)->contents)" as we should.
There are two instances where we act on fix_current_buffer and call
Fset_buffer, and I believe the relevant one to be this:
--8<---------------cut here---------------start------------->8---
if (NILP (first_event))
{
first_event = key;
/* Even if first_event does not specify a particular
window/position, it's important to recompute the maps here
since a long time might have passed since we entered
read_key_sequence, and a timer (or process-filter or
special-event-map, ...) might have switched the current buffer
or the selected window from under us in the mean time. */
if (fix_current_buffer
&& (XBUFFER (XWINDOW (selected_window)->contents)
!= current_buffer))
Fset_buffer (XWINDOW (selected_window)->contents);
current_binding = active_maps (first_event, Qnil);
}
--8<---------------cut here---------------end--------------->8---
read_key_sequence does a lot of replaying. The point of this code, I
think, is to handle the case where either we have just called read_char
for the very first time, or we are replaying with mock_input==0.
The branch of code Spencer has pointed out handles the case of being
interrupted while initializing the terminal. In contrast to the above,
that's a case in which we are not calling read_char for the very first
time and are replaying with mock_input==1.
Given that these situations are disjoint, I believe that rather than
changing control flow, we need to add an additional fix_current_buffer
check, as is done in the attached patch.
Spencer, does this fix the problem for you?
(I don't understand the full sequence of occurrences in the case we are
considering because the comment talks about read_char returning "the new
buffer" but what it actually returns is the 'q' that's typed.)
--
Sean Whitton
[0001-read_key_sequence-Additional-check-for-fix_current_b.patch (text/x-diff, attachment)]
This bug report was last modified 15 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.