For help commands, ensure all keys of a mouse sequence are reported.

This solves the problem where read_key_sequence initializes and uses a global
buffer raw_keybuf, yet is called recusrsively.  The initialization is now done
elsewhere, avoiding the reinitialization of that global buffer.

* src/keyboard.c (command_loop_1, read_key_sequence_vs): Initialize
raw_event_count before calling read_key_sequence.
(read_char_x_menu_prompt): Call x_popup_menu_1 in place of Fx_popup_menu.
(init_raw_keybuf_count): New function.
(read_key_sequence): Remove initialization of raw_event_count.  Add a missing
GROW_RAW_KEYBUF invocation.

* src/keyboard.h: (init_raw_keybuf_count): New declaration.

* src/menu.c: (x_popup_menu_1): New function with the functionality of the
former Fx_popup_menu.
(Fx_popup_menu): Replace with function which initializes raw_event_count then
calls x_popup_menu_1.

* src/menu.h: (x_popup_menu_1): New declaration.
This commit is contained in:
Alan Mackenzie 2017-12-02 10:00:56 +00:00
parent 4856ee1717
commit bc092fcaea
4 changed files with 84 additions and 88 deletions

View file

@ -43,6 +43,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "systime.h"
#include "atimer.h"
#include "process.h"
#include "menu.h"
#include <errno.h>
#ifdef HAVE_PTHREAD
@ -121,17 +122,12 @@ ptrdiff_t this_command_key_count;
/* This vector is used as a buffer to record the events that were actually read
by read_key_sequence. */
static Lisp_Object raw_keybuf_buffer;
static int raw_keybuf_count_buffer;
static Lisp_Object *raw_keybuf = &raw_keybuf_buffer;
static int *raw_keybuf_count = &raw_keybuf_count_buffer;
static Lisp_Object raw_keybuf;
static int raw_keybuf_count;
#define GROW_RAW_KEYBUF(inc) \
if (*raw_keybuf_count > ASIZE (*raw_keybuf) - (inc)) \
*raw_keybuf = \
larger_vector (*raw_keybuf, \
(inc) + *raw_keybuf_count - ASIZE (*raw_keybuf), \
-1)
#define GROW_RAW_KEYBUF \
if (raw_keybuf_count == ASIZE (raw_keybuf)) \
raw_keybuf = larger_vector (raw_keybuf, 1, -1)
/* Number of elements of this_command_keys
that precede this key sequence. */
@ -1370,8 +1366,7 @@ command_loop_1 (void)
Vthis_command_keys_shift_translated = Qnil;
/* Read next key sequence; i gets its length. */
raw_keybuf_count = &raw_keybuf_count_buffer; /* For safety */
raw_keybuf = &raw_keybuf_buffer; /* Ditto */
raw_keybuf_count = 0;
i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
Qnil, 0, 1, 1, 0);
@ -8460,7 +8455,7 @@ read_char_x_menu_prompt (Lisp_Object map,
/* Display the menu and get the selection. */
Lisp_Object value;
value = Fx_popup_menu (prev_event, get_keymap (map, 0, 1));
value = x_popup_menu_1 (prev_event, get_keymap (map, 0, 1));
if (CONSP (value))
{
Lisp_Object tem;
@ -8870,6 +8865,11 @@ test_undefined (Lisp_Object binding)
&& EQ (Fcommand_remapping (binding, Qnil, Qnil), Qundefined)));
}
void init_raw_keybuf_count (void)
{
raw_keybuf_count = 0;
}
/* Read a sequence of keys that ends with a non prefix character,
storing it in KEYBUF, a buffer of size BUFSIZE.
Prompt with PROMPT.
@ -8920,11 +8920,6 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
/* How many keys there are in the current key sequence. */
int t;
int *outer_raw_keybuf_count;
Lisp_Object *outer_raw_keybuf;
int inner_raw_keybuf_count_buffer;
Lisp_Object inner_raw_keybuf_buffer = Fmake_vector (make_number (30), Qnil);
/* The length of the echo buffer when we started reading, and
the length of this_command_keys when we started reading. */
ptrdiff_t echo_start UNINIT;
@ -8985,7 +8980,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
/* List of events for which a fake prefix key has been generated. */
Lisp_Object fake_prefixed_keys = Qnil;
*raw_keybuf_count = 0;
/* raw_keybuf_count is now initialized in (most of) the callers of
read_key_sequence. This is so that in a recursive call (for
mouse menus) a spurious initialization doesn't erase the contents
of raw_keybuf created by the outer call. */
/* raw_keybuf_count = 0; */
last_nonmenu_event = Qnil;
@ -9157,23 +9156,11 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
{
KBOARD *interrupted_kboard = current_kboard;
struct frame *interrupted_frame = SELECTED_FRAME ();
int i;
outer_raw_keybuf_count = raw_keybuf_count;
outer_raw_keybuf = raw_keybuf;
inner_raw_keybuf_count_buffer = 0;
raw_keybuf_count = &inner_raw_keybuf_count_buffer;
raw_keybuf = &inner_raw_keybuf_buffer;
/* Calling read_char with COMMANDFLAG = -2 avoids
redisplay in read_char and its subroutines. */
key = read_char (prevent_redisplay ? -2 : NILP (prompt),
current_binding, last_nonmenu_event,
&used_mouse_menu, NULL);
raw_keybuf_count = outer_raw_keybuf_count;
raw_keybuf = outer_raw_keybuf;
GROW_RAW_KEYBUF (inner_raw_keybuf_count_buffer);
for (i = 0; i < inner_raw_keybuf_count_buffer; i++)
ASET (*raw_keybuf, (*raw_keybuf_count)++,
AREF (inner_raw_keybuf_buffer, i));
if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
/* When switching to a new tty (with a new keyboard),
read_char returns the new buffer, rather than -2
@ -9281,9 +9268,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
&& XINT (key) == quit_char
&& current_buffer != starting_buffer)
{
GROW_RAW_KEYBUF (1);
ASET (*raw_keybuf, *raw_keybuf_count, key);
(*raw_keybuf_count)++;
GROW_RAW_KEYBUF;
ASET (raw_keybuf, raw_keybuf_count, key);
raw_keybuf_count++;
keybuf[t++] = key;
mock_input = t;
Vquit_flag = Qnil;
@ -9322,9 +9309,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
current_binding = active_maps (first_event);
}
GROW_RAW_KEYBUF (1);
ASET (*raw_keybuf, *raw_keybuf_count, key);
(*raw_keybuf_count)++;
GROW_RAW_KEYBUF;
ASET (raw_keybuf, raw_keybuf_count, key);
raw_keybuf_count++;
}
/* Clicks in non-text areas get prefixed by the symbol
@ -9370,9 +9357,9 @@ read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
&& BUFFERP (XWINDOW (window)->contents)
&& XBUFFER (XWINDOW (window)->contents) != current_buffer)
{
GROW_RAW_KEYBUF (1);
ASET (*raw_keybuf, *raw_keybuf_count, key);
(*raw_keybuf_count)++;
GROW_RAW_KEYBUF;
ASET (raw_keybuf, raw_keybuf_count, key);
raw_keybuf_count++;
keybuf[t] = key;
mock_input = t + 1;
@ -9865,6 +9852,7 @@ read_key_sequence_vs (Lisp_Object prompt, Lisp_Object continue_echo,
cancel_hourglass ();
#endif
raw_keybuf_count = 0;
i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
prompt, ! NILP (dont_downcase_last),
! NILP (can_return_switch_frame), 0, 0);
@ -10145,7 +10133,7 @@ shows the events before all translations (except for input methods).
The value is always a vector. */)
(void)
{
return Fvector (*raw_keybuf_count, XVECTOR (*raw_keybuf)->contents);
return Fvector (raw_keybuf_count, XVECTOR (raw_keybuf)->contents);
}
DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
@ -11290,8 +11278,8 @@ syms_of_keyboard (void)
this_command_keys = Fmake_vector (make_number (40), Qnil);
staticpro (&this_command_keys);
raw_keybuf_buffer = Fmake_vector (make_number (30), Qnil);
staticpro (raw_keybuf);
raw_keybuf = Fmake_vector (make_number (30), Qnil);
staticpro (&raw_keybuf);
DEFSYM (Qcommand_execute, "command-execute");
DEFSYM (Qinternal_echo_keystrokes_prefix, "internal-echo-keystrokes-prefix");

View file

@ -438,6 +438,7 @@ extern unsigned int timers_run;
extern bool menu_separator_name_p (const char *);
extern bool parse_menu_item (Lisp_Object, int);
extern void init_raw_keybuf_count (void);
extern KBOARD *allocate_kboard (Lisp_Object);
extern void delete_kboard (KBOARD *);
extern void not_single_kboard_state (KBOARD *);

View file

@ -1112,51 +1112,8 @@ into menu items. */)
return Qnil;
}
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
doc: /* Pop up a deck-of-cards menu and return user's selection.
POSITION is a position specification. This is either a mouse button event
or a list ((XOFFSET YOFFSET) WINDOW)
where XOFFSET and YOFFSET are positions in pixels from the top left
corner of WINDOW. (WINDOW may be a window or a frame object.)
This controls the position of the top left of the menu as a whole.
If POSITION is t, it means to use the current mouse position.
MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
The menu items come from key bindings that have a menu string as well as
a definition; actually, the "definition" in such a key binding looks like
\(STRING . REAL-DEFINITION). To give the menu a title, put a string into
the keymap as a top-level element.
If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
Otherwise, REAL-DEFINITION should be a valid key binding definition.
You can also use a list of keymaps as MENU.
Then each keymap makes a separate pane.
When MENU is a keymap or a list of keymaps, the return value is the
list of events corresponding to the user's choice. Note that
`x-popup-menu' does not actually execute the command bound to that
sequence of events.
Alternatively, you can specify a menu of multiple panes
with a list of the form (TITLE PANE1 PANE2...),
where each pane is a list of form (TITLE ITEM1 ITEM2...).
Each ITEM is normally a cons cell (STRING . VALUE);
but a string can appear as an item--that makes a nonselectable line
in the menu.
With this form of menu, the return value is VALUE from the chosen item.
If POSITION is nil, don't display the menu at all, just precalculate the
cached information about equivalent key sequences.
If the user gets rid of the menu without making a valid choice, for
instance by clicking the mouse away from a valid choice or by typing
keyboard input, then this normally results in a quit and
`x-popup-menu' does not return. But if POSITION is a mouse button
event (indicating that the user invoked the menu with the mouse) then
no quit occurs and `x-popup-menu' returns nil. */)
(Lisp_Object position, Lisp_Object menu)
Lisp_Object
x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
{
Lisp_Object keymap, tem, tem2;
int xpos = 0, ypos = 0;
@ -1443,6 +1400,55 @@ no quit occurs and `x-popup-menu' returns nil. */)
return selection;
}
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
doc: /* Pop up a deck-of-cards menu and return user's selection.
POSITION is a position specification. This is either a mouse button event
or a list ((XOFFSET YOFFSET) WINDOW)
where XOFFSET and YOFFSET are positions in pixels from the top left
corner of WINDOW. (WINDOW may be a window or a frame object.)
This controls the position of the top left of the menu as a whole.
If POSITION is t, it means to use the current mouse position.
MENU is a specifier for a menu. For the simplest case, MENU is a keymap.
The menu items come from key bindings that have a menu string as well as
a definition; actually, the "definition" in such a key binding looks like
\(STRING . REAL-DEFINITION). To give the menu a title, put a string into
the keymap as a top-level element.
If REAL-DEFINITION is nil, that puts a nonselectable string in the menu.
Otherwise, REAL-DEFINITION should be a valid key binding definition.
You can also use a list of keymaps as MENU.
Then each keymap makes a separate pane.
When MENU is a keymap or a list of keymaps, the return value is the
list of events corresponding to the user's choice. Note that
`x-popup-menu' does not actually execute the command bound to that
sequence of events.
Alternatively, you can specify a menu of multiple panes
with a list of the form (TITLE PANE1 PANE2...),
where each pane is a list of form (TITLE ITEM1 ITEM2...).
Each ITEM is normally a cons cell (STRING . VALUE);
but a string can appear as an item--that makes a nonselectable line
in the menu.
With this form of menu, the return value is VALUE from the chosen item.
If POSITION is nil, don't display the menu at all, just precalculate the
cached information about equivalent key sequences.
If the user gets rid of the menu without making a valid choice, for
instance by clicking the mouse away from a valid choice or by typing
keyboard input, then this normally results in a quit and
`x-popup-menu' does not return. But if POSITION is a mouse button
event (indicating that the user invoked the menu with the mouse) then
no quit occurs and `x-popup-menu' returns nil. */)
(Lisp_Object position, Lisp_Object menu)
{
init_raw_keybuf_count ();
return x_popup_menu_1 (position, menu);
}
/* If F's terminal is not capable of displaying a popup dialog,
emulate it with a menu. */

View file

@ -60,4 +60,5 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, int,
extern Lisp_Object tty_menu_show (struct frame *, int, int, int,
Lisp_Object, const char **);
extern ptrdiff_t menu_item_width (const unsigned char *);
extern Lisp_Object x_popup_menu_1 (Lisp_Object position, Lisp_Object menu);
#endif /* MENU_H */