Subject: 24.0.50; read-event in `repeat' command

From: "Drew Adams" <[email-masked]>
Date: Mon, 24 May 2010 08:11:37 -0700

In GNU Emacs 24.0.50.1 (i386-mingw-nt5.1.2600)
 of 2010-05-23 on G41R2F1
Windowing system distributor `Microsoft Corp.', version 5.1.2600
configured using `configure --with-gcc (3.4) --no-opt --cflags -Ic:/xpm/include'
 
I use popup frames a lot.  By default, that is how a buffer gets displayed in my
setup.

I'm also on MS Windows, which has the property that a newly created frame is
always selected (obtains the focus). This means that displaying a buffer is
different, depending on whether its frame already exists. If it does, then the
focus (typically) does not change to the buffer's frame.  If it does not, then
the focus moves there. I work around this focus-grabbing annoyance sometimes by
using `select-frame-set-input-focus' at appropriate places. (Ugh!)

Anyway, the problem I have is with the `repeat' command. Presumably,
it tries to be sensitive to actual user events, such as typing a character, but
ignore other, non-user events.  This does not work for me in some
cases - an automatic `switch-frame' event is causing it to stop repeating.

I have a command that displays a buffer in its own frame (the same frame or
another, possibly new, frame). I make it repeatable using `repeat', and I bind
it to a key, say `f'.  That works fine in general: hitting `f f f...' continues
to display buffers - in new frames or existing frames.  No problem.

But in some cases my command also pops up an additional buffer, in another
frame.  In those cases the repetition breaks as soon as that second buffer is
displayed. Hitting `f' at that point just inserts an `f' character (in that
buffer if it was selected, else in the first buffer displayed by `f').  It does
not matter whether the second buffer and its frame already exist or not.

I mentioned the frame focus above, but that is apparently not the problem. It
does not matter whether the `f' command opens the first buffer in a new frame or
an existing frame, and likewise for the second buffer. And it does not matter
whether the second buffer is selected (and its frame focused) or not.

It is only when hitting `f' opens also a second buffer that a subsequent `f'
just inserts.

However, if I make a copy of the definition of command `repeat' and change only
its `read-event' to `read-char-exclusive', then the problem goes away.  So some
event being read is being tested and found to be different from the `f' last
input event, thus ending the repetition.

I'm guessing that this is what happens: The `read-event' reads the `f' and
repeats the command, which displays the first and second buffers. I would think
there would be a `switch-frame' event associated with each buffer display, but
maybe not. In any case, if there is a `switch-frame' for the first buffer
display it is ignored, but the `switch-frame' for the second buffer display
causes repetition to stop.

It is difficult to use the debugger with `repeat', so I copied the code and
inserted a call to `message' after the `read-event'.  It shows clearly that
display of the second buffer causes the event read to be a `switch-frame'.

Do we intentionally use `read-event' here (instead of `read-char-exclusive') in
order to let `repeat' work with other user events besides just char input (e.g.
mouse clicks)?  If so, then changing `read-event' to `read-char-exclusive' would
not be the correct fix, but what would?  This is not clear to me.  

`read-event' has been present in this code since at least Emacs 20, but this
code does not correctly handle `switch-frame' events.  Real user events need to
be distinguished from events such as `switch-frame' that can be generated by
code.

Is changing `read-event' to `read-char-exclusive' the proper fix for this bug?
It works for me.  If it is not the right fix, then what is?

If it is important for some use reason to keep `read-event', and no fix is found
that would DTRT to distinguish real user events from events such as
`switch-frame', then could we at least use `(funcall repeat-read-function)'
instead of `(read-event)', so that code that wants to be sensitive to only char
events can bind `repeat-read-function' to `read-char-exclusive' around the call
to `repeat'?

The default value of such a var could be `read-event', if that's deemed the best
default, but we at least need some way to make `repeat' ignore non-char events
(if we cannot find a way to make it ignore non-user events).