From: Alan Mackenzie Date: Sat, 2 Dec 2017 10:00:56 +0000 (+0000) Subject: For help commands, ensure all keys of a mouse sequence are reported. X-Git-Tag: emacs-27.0.90~6103 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=bc092fcaea7268f2339f0e92720a37e62cdca5b2;p=emacs.git 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. --- diff --git a/src/keyboard.c b/src/keyboard.c index b18dc1abbe7..375aa4f6067 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -43,6 +43,7 @@ along with GNU Emacs. If not, see . */ #include "systime.h" #include "atimer.h" #include "process.h" +#include "menu.h" #include #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; - -#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) +static Lisp_Object raw_keybuf; +static int raw_keybuf_count; + +#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"); diff --git a/src/keyboard.h b/src/keyboard.h index 662d8e4a4f6..c232e778e21 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -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 *); diff --git a/src/menu.c b/src/menu.c index d569b4b29b5..b40c2c04ce7 100644 --- a/src/menu.c +++ b/src/menu.c @@ -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. */ diff --git a/src/menu.h b/src/menu.h index 1469cc87d99..3335616338d 100644 --- a/src/menu.h +++ b/src/menu.h @@ -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 */