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.
There is no need to reopen the bug first.
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)]
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79513; Package
emacs.
(Sun, 09 Nov 2025 11:08:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 79513 <at> debbugs.gnu.org (full text, mbox):
Hello Spencer,
I just wanted to ping you about this, have you had a chance to try my
patch? I think my reproduction is good enough to install the change but
it would still be good to confirm it fixes things for you, too, before
doing so.
On Tue 21 Oct 2025 at 06:06pm +01, Sean Whitton wrote:
> 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
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79513; Package
emacs.
(Thu, 13 Nov 2025 17:14:02 GMT)
Full text and
rfc822 format available.
Message #14 received at 79513 <at> debbugs.gnu.org (full text, mbox):
Sean Whitton <spwhitton <at> spwhitton.name> writes:
> Hello Spencer,
>
> I just wanted to ping you about this, have you had a chance to try my
> patch? I think my reproduction is good enough to install the change but
> it would still be good to confirm it fixes things for you, too, before
> doing so.
I tried your patch and it fixes the bug for me as well. Looking it
over, it seems reasonable, I think we should install it.
Reply sent
to
Sean Whitton <spwhitton <at> spwhitton.name>:
You have taken responsibility.
(Thu, 13 Nov 2025 17:19:02 GMT)
Full text and
rfc822 format available.
Notification sent
to
Spencer Baugh <sbaugh <at> janestreet.com>:
bug acknowledged by developer.
(Thu, 13 Nov 2025 17:19:02 GMT)
Full text and
rfc822 format available.
Message #19 received at 79513-done <at> debbugs.gnu.org (full text, mbox):
Version: 31.1
Hello,
On Thu 13 Nov 2025 at 12:13pm -05, Spencer Baugh wrote:
> Sean Whitton <spwhitton <at> spwhitton.name> writes:
>
>> Hello Spencer,
>>
>> I just wanted to ping you about this, have you had a chance to try my
>> patch? I think my reproduction is good enough to install the change but
>> it would still be good to confirm it fixes things for you, too, before
>> doing so.
>
> I tried your patch and it fixes the bug for me as well. Looking it
> over, it seems reasonable, I think we should install it.
Many thanks for reviewing, now installed, and closing.
--
Sean Whitton
This bug report was last modified 18 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.