diff options
| author | Eli Zaretskii | 2013-10-08 17:28:37 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2013-10-08 17:28:37 +0300 |
| commit | 4a48e94d50bad36ed872725db8d8cddbac5a9f47 (patch) | |
| tree | 2946df7bacbe036ac9fef86e1a3cfcfe1caa94a0 /src | |
| parent | 493a197846a4483f21605950e6214e42ecb6fc62 (diff) | |
| download | emacs-4a48e94d50bad36ed872725db8d8cddbac5a9f47.tar.gz emacs-4a48e94d50bad36ed872725db8d8cddbac5a9f47.zip | |
Horizontal keys in TTY menus work.
Diffstat (limited to 'src')
| -rw-r--r-- | src/menu.c | 29 | ||||
| -rw-r--r-- | src/menu.h | 3 | ||||
| -rw-r--r-- | src/term.c | 132 |
3 files changed, 147 insertions, 17 deletions
diff --git a/src/menu.c b/src/menu.c index 2c787e00b6f..f741d686cd1 100644 --- a/src/menu.c +++ b/src/menu.c | |||
| @@ -1036,8 +1036,8 @@ find_and_return_menu_selection (struct frame *f, bool keymaps, void *client_data | |||
| 1036 | } | 1036 | } |
| 1037 | #endif /* HAVE_NS */ | 1037 | #endif /* HAVE_NS */ |
| 1038 | 1038 | ||
| 1039 | static int | 1039 | int |
| 1040 | item_width (const char *str) | 1040 | menu_item_width (const char *str) |
| 1041 | { | 1041 | { |
| 1042 | int len; | 1042 | int len; |
| 1043 | const char *p; | 1043 | const char *p; |
| @@ -1104,7 +1104,7 @@ into menu items. */) | |||
| 1104 | if (XINT (pos) <= col | 1104 | if (XINT (pos) <= col |
| 1105 | /* We use <= so the blank between 2 items on a TTY is | 1105 | /* We use <= so the blank between 2 items on a TTY is |
| 1106 | considered part of the previous item. */ | 1106 | considered part of the previous item. */ |
| 1107 | && col <= XINT (pos) + item_width (SSDATA (str))) | 1107 | && col <= XINT (pos) + menu_item_width (SSDATA (str))) |
| 1108 | { | 1108 | { |
| 1109 | item = AREF (items, i); | 1109 | item = AREF (items, i); |
| 1110 | return item; | 1110 | return item; |
| @@ -1160,7 +1160,7 @@ event (indicating that the user invoked the menu with the mouse) then | |||
| 1160 | no quit occurs and `x-popup-menu' returns nil. */) | 1160 | no quit occurs and `x-popup-menu' returns nil. */) |
| 1161 | (Lisp_Object position, Lisp_Object menu) | 1161 | (Lisp_Object position, Lisp_Object menu) |
| 1162 | { | 1162 | { |
| 1163 | Lisp_Object keymap, tem; | 1163 | Lisp_Object keymap, tem, tem2; |
| 1164 | int xpos = 0, ypos = 0; | 1164 | int xpos = 0, ypos = 0; |
| 1165 | Lisp_Object title; | 1165 | Lisp_Object title; |
| 1166 | const char *error_name = NULL; | 1166 | const char *error_name = NULL; |
| @@ -1169,6 +1169,7 @@ no quit occurs and `x-popup-menu' returns nil. */) | |||
| 1169 | Lisp_Object x, y, window; | 1169 | Lisp_Object x, y, window; |
| 1170 | bool keymaps = 0; | 1170 | bool keymaps = 0; |
| 1171 | bool for_click = 0; | 1171 | bool for_click = 0; |
| 1172 | bool kbd_menu_navigation = 0; | ||
| 1172 | ptrdiff_t specpdl_count = SPECPDL_INDEX (); | 1173 | ptrdiff_t specpdl_count = SPECPDL_INDEX (); |
| 1173 | struct gcpro gcpro1; | 1174 | struct gcpro gcpro1; |
| 1174 | 1175 | ||
| @@ -1202,6 +1203,22 @@ no quit occurs and `x-popup-menu' returns nil. */) | |||
| 1202 | for_click = 1; | 1203 | for_click = 1; |
| 1203 | tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ | 1204 | tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ |
| 1204 | window = Fcar (tem); /* POSN_WINDOW (tem) */ | 1205 | window = Fcar (tem); /* POSN_WINDOW (tem) */ |
| 1206 | tem2 = Fcar (Fcdr (tem)); /* POSN_POSN (tem) */ | ||
| 1207 | /* The kbd_menu_navigation flag is set when the menu was | ||
| 1208 | invoked by F10, which probably means they have no | ||
| 1209 | mouse. In that case, we let them switch between | ||
| 1210 | top-level menu-bar menus by using C-f/C-b and | ||
| 1211 | horizontal arrow keys, since they cannot click the | ||
| 1212 | mouse to open a different submenu. This flag is only | ||
| 1213 | supported by tty_menu_show. We set it when POSITION | ||
| 1214 | and last_nonmenu_event are different, which means we | ||
| 1215 | constructed POSITION by hand (in popup-menu, see | ||
| 1216 | menu-bar.el) to look like a mouse click on the menu bar | ||
| 1217 | event. */ | ||
| 1218 | if (!EQ (POSN_POSN (last_nonmenu_event), | ||
| 1219 | POSN_POSN (position)) | ||
| 1220 | && CONSP (tem2) && EQ (Fcar (tem2), Qmenu_bar)) | ||
| 1221 | kbd_menu_navigation = 1; | ||
| 1205 | tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ | 1222 | tem = Fcar (Fcdr (Fcdr (tem))); /* POSN_WINDOW_POSN (tem) */ |
| 1206 | x = Fcar (tem); | 1223 | x = Fcar (tem); |
| 1207 | y = Fcdr (tem); | 1224 | y = Fcdr (tem); |
| @@ -1434,8 +1451,8 @@ no quit occurs and `x-popup-menu' returns nil. */) | |||
| 1434 | else | 1451 | else |
| 1435 | #endif | 1452 | #endif |
| 1436 | if (FRAME_TERMCAP_P (f)) | 1453 | if (FRAME_TERMCAP_P (f)) |
| 1437 | selection = tty_menu_show (f, xpos, ypos, for_click, | 1454 | selection = tty_menu_show (f, xpos, ypos, for_click, keymaps, title, |
| 1438 | keymaps, title, &error_name); | 1455 | kbd_menu_navigation, &error_name); |
| 1439 | 1456 | ||
| 1440 | #ifdef HAVE_NS | 1457 | #ifdef HAVE_NS |
| 1441 | unbind_to (specpdl_count, Qnil); | 1458 | unbind_to (specpdl_count, Qnil); |
diff --git a/src/menu.h b/src/menu.h index cdc1838ff9f..9b3b71d757e 100644 --- a/src/menu.h +++ b/src/menu.h | |||
| @@ -52,5 +52,6 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, bool, bool, | |||
| 52 | extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, | 52 | extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, |
| 53 | Lisp_Object, const char **, Time); | 53 | Lisp_Object, const char **, Time); |
| 54 | extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int, | 54 | extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int, |
| 55 | Lisp_Object, const char **); | 55 | Lisp_Object, int, const char **); |
| 56 | extern int menu_item_width (const char *); | ||
| 56 | #endif /* MENU_H */ | 57 | #endif /* MENU_H */ |
diff --git a/src/term.c b/src/term.c index d5c5f6ed796..8515edf88a5 100644 --- a/src/term.c +++ b/src/term.c | |||
| @@ -2789,6 +2789,8 @@ DEFUN ("gpm-mouse-stop", Fgpm_mouse_stop, Sgpm_mouse_stop, | |||
| 2789 | #define TTYM_SUCCESS 1 | 2789 | #define TTYM_SUCCESS 1 |
| 2790 | #define TTYM_NO_SELECT 2 | 2790 | #define TTYM_NO_SELECT 2 |
| 2791 | #define TTYM_IA_SELECT 3 | 2791 | #define TTYM_IA_SELECT 3 |
| 2792 | #define TTYM_NEXT 4 | ||
| 2793 | #define TTYM_PREV 5 | ||
| 2792 | 2794 | ||
| 2793 | /* These hold text of the current and the previous menu help messages. */ | 2795 | /* These hold text of the current and the previous menu help messages. */ |
| 2794 | static const char *menu_help_message, *prev_menu_help_message; | 2796 | static const char *menu_help_message, *prev_menu_help_message; |
| @@ -3174,7 +3176,8 @@ screen_update (struct frame *f, struct glyph_matrix *mtx) | |||
| 3174 | puts us. We only consider mouse movement and click events and | 3176 | puts us. We only consider mouse movement and click events and |
| 3175 | keyboard movement commands; the rest are ignored. | 3177 | keyboard movement commands; the rest are ignored. |
| 3176 | 3178 | ||
| 3177 | Value is -1 if C-g was pressed, 1 if an item was selected, zero | 3179 | Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3 |
| 3180 | if we need to move to the next or previous menu-bar menu, zero | ||
| 3178 | otherwise. */ | 3181 | otherwise. */ |
| 3179 | static int | 3182 | static int |
| 3180 | read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | 3183 | read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, |
| @@ -3219,9 +3222,15 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | |||
| 3219 | *y = my; | 3222 | *y = my; |
| 3220 | } | 3223 | } |
| 3221 | else if (EQ (cmd, Qtty_menu_next_menu)) | 3224 | else if (EQ (cmd, Qtty_menu_next_menu)) |
| 3222 | *x += 1; | 3225 | { |
| 3226 | usable_input = 0; | ||
| 3227 | st = 2; | ||
| 3228 | } | ||
| 3223 | else if (EQ (cmd, Qtty_menu_prev_menu)) | 3229 | else if (EQ (cmd, Qtty_menu_prev_menu)) |
| 3224 | *x -= 1; | 3230 | { |
| 3231 | usable_input = 0; | ||
| 3232 | st = 3; | ||
| 3233 | } | ||
| 3225 | else if (EQ (cmd, Qtty_menu_next_item)) | 3234 | else if (EQ (cmd, Qtty_menu_next_item)) |
| 3226 | { | 3235 | { |
| 3227 | if (*y < max_y) | 3236 | if (*y < max_y) |
| @@ -3255,10 +3264,11 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, | |||
| 3255 | } | 3264 | } |
| 3256 | 3265 | ||
| 3257 | /* Display menu, wait for user's response, and return that response. */ | 3266 | /* Display menu, wait for user's response, and return that response. */ |
| 3258 | int | 3267 | static int |
| 3259 | tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | 3268 | tty_menu_activate (tty_menu *menu, int *pane, int *selidx, |
| 3260 | int x0, int y0, char **txt, | 3269 | int x0, int y0, char **txt, |
| 3261 | void (*help_callback)(char const *, int, int)) | 3270 | void (*help_callback)(char const *, int, int), |
| 3271 | int kbd_navigation) | ||
| 3262 | { | 3272 | { |
| 3263 | struct tty_menu_state *state; | 3273 | struct tty_menu_state *state; |
| 3264 | int statecount, x, y, i, b, leave, result, onepane; | 3274 | int statecount, x, y, i, b, leave, result, onepane; |
| @@ -3353,6 +3363,7 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3353 | input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time); | 3363 | input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time); |
| 3354 | if (input_status) | 3364 | if (input_status) |
| 3355 | { | 3365 | { |
| 3366 | leave = 1; | ||
| 3356 | if (input_status == -1) | 3367 | if (input_status == -1) |
| 3357 | { | 3368 | { |
| 3358 | /* Remove the last help-echo, so that it doesn't | 3369 | /* Remove the last help-echo, so that it doesn't |
| @@ -3360,7 +3371,20 @@ tty_menu_activate (tty_menu *menu, int *pane, int *selidx, | |||
| 3360 | show_help_echo (Qnil, Qnil, Qnil, Qnil); | 3371 | show_help_echo (Qnil, Qnil, Qnil, Qnil); |
| 3361 | result = TTYM_NO_SELECT; | 3372 | result = TTYM_NO_SELECT; |
| 3362 | } | 3373 | } |
| 3363 | leave = 1; | 3374 | else if (input_status == 2) |
| 3375 | { | ||
| 3376 | if (kbd_navigation) | ||
| 3377 | result = TTYM_NEXT; | ||
| 3378 | else | ||
| 3379 | leave = 0; | ||
| 3380 | } | ||
| 3381 | else if (input_status == 3) | ||
| 3382 | { | ||
| 3383 | if (kbd_navigation) | ||
| 3384 | result = TTYM_PREV; | ||
| 3385 | else | ||
| 3386 | leave = 0; | ||
| 3387 | } | ||
| 3364 | } | 3388 | } |
| 3365 | if (sf->mouse_moved && input_status != -1) | 3389 | if (sf->mouse_moved && input_status != -1) |
| 3366 | { | 3390 | { |
| @@ -3509,15 +3533,97 @@ tty_pop_down_menu (Lisp_Object arg) | |||
| 3509 | unblock_input (); | 3533 | unblock_input (); |
| 3510 | } | 3534 | } |
| 3511 | 3535 | ||
| 3536 | /* Return the zero-based index of the last menu-bar item on frame F. */ | ||
| 3537 | static int | ||
| 3538 | tty_menu_last_menubar_item (struct frame *f) | ||
| 3539 | { | ||
| 3540 | int i = 0; | ||
| 3541 | |||
| 3542 | eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f)); | ||
| 3543 | if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f)) | ||
| 3544 | { | ||
| 3545 | Lisp_Object items = FRAME_MENU_BAR_ITEMS (f); | ||
| 3546 | |||
| 3547 | while (i < ASIZE (items)) | ||
| 3548 | { | ||
| 3549 | Lisp_Object str; | ||
| 3550 | |||
| 3551 | str = AREF (items, i + 1); | ||
| 3552 | if (NILP (str)) | ||
| 3553 | break; | ||
| 3554 | i += 4; | ||
| 3555 | } | ||
| 3556 | i -= 4; /* went one too far */ | ||
| 3557 | } | ||
| 3558 | return i; | ||
| 3559 | } | ||
| 3560 | |||
| 3561 | /* Find in frame F's menu bar the menu item that is next or previous | ||
| 3562 | to the item at X/Y, and return that item's position in X/Y. WHICH | ||
| 3563 | says which one--next or previous--item to look for. X and Y are | ||
| 3564 | measured in character cells. This should only be called on TTY | ||
| 3565 | frames. */ | ||
| 3566 | static void | ||
| 3567 | tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y) | ||
| 3568 | { | ||
| 3569 | eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f)); | ||
| 3570 | if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f)) | ||
| 3571 | { | ||
| 3572 | Lisp_Object items = FRAME_MENU_BAR_ITEMS (f); | ||
| 3573 | int last_i = tty_menu_last_menubar_item (f); | ||
| 3574 | int i, prev_x; | ||
| 3575 | |||
| 3576 | /* This loop assumes a single menu-bar line, and will fail to | ||
| 3577 | find an item if it is not in the first line. Note that | ||
| 3578 | make_lispy_event in keyboard.c makes the same assumption. */ | ||
| 3579 | for (i = 0, prev_x = -1; i < ASIZE (items); i += 4) | ||
| 3580 | { | ||
| 3581 | Lisp_Object pos, str; | ||
| 3582 | int ix; | ||
| 3583 | |||
| 3584 | str = AREF (items, i + 1); | ||
| 3585 | pos = AREF (items, i + 3); | ||
| 3586 | if (NILP (str)) | ||
| 3587 | return; | ||
| 3588 | ix = XINT (pos); | ||
| 3589 | if (ix <= *x | ||
| 3590 | /* We use <= so the blank between 2 items on a TTY is | ||
| 3591 | considered part of the previous item. */ | ||
| 3592 | && *x <= ix + menu_item_width (SSDATA (str))) | ||
| 3593 | { | ||
| 3594 | /* Found current item. Now compute the X coordinate of | ||
| 3595 | the previous or next item. */ | ||
| 3596 | if (which == TTYM_NEXT) | ||
| 3597 | { | ||
| 3598 | if (i < last_i) | ||
| 3599 | *x = XINT (AREF (items, i + 4 + 3)); | ||
| 3600 | else | ||
| 3601 | *x = 0; /* wrap around to the first item */ | ||
| 3602 | } | ||
| 3603 | else if (prev_x < 0) | ||
| 3604 | { | ||
| 3605 | /* Wrap around to the last item. */ | ||
| 3606 | *x = XINT (AREF (items, last_i + 3)); | ||
| 3607 | } | ||
| 3608 | else | ||
| 3609 | *x = prev_x; | ||
| 3610 | return; | ||
| 3611 | } | ||
| 3612 | prev_x = ix; | ||
| 3613 | } | ||
| 3614 | } | ||
| 3615 | } | ||
| 3616 | |||
| 3512 | Lisp_Object | 3617 | Lisp_Object |
| 3513 | tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, | 3618 | tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, |
| 3514 | Lisp_Object title, const char **error_name) | 3619 | Lisp_Object title, int kbd_navigation, const char **error_name) |
| 3515 | { | 3620 | { |
| 3516 | tty_menu *menu; | 3621 | tty_menu *menu; |
| 3517 | int pane, selidx, lpane, status; | 3622 | int pane, selidx, lpane, status; |
| 3518 | Lisp_Object entry, pane_prefix; | 3623 | Lisp_Object entry, pane_prefix; |
| 3519 | char *datap; | 3624 | char *datap; |
| 3520 | int ulx, uly, width, height; | 3625 | int ulx, uly, width, height; |
| 3626 | int item_x, item_y; | ||
| 3521 | int dispwidth, dispheight; | 3627 | int dispwidth, dispheight; |
| 3522 | int i, j, lines, maxlines; | 3628 | int i, j, lines, maxlines; |
| 3523 | int maxwidth; | 3629 | int maxwidth; |
| @@ -3551,8 +3657,8 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, | |||
| 3551 | inhibit_garbage_collection (); | 3657 | inhibit_garbage_collection (); |
| 3552 | 3658 | ||
| 3553 | /* Adjust coordinates to be root-window-relative. */ | 3659 | /* Adjust coordinates to be root-window-relative. */ |
| 3554 | x += f->left_pos; | 3660 | item_x = x += f->left_pos; |
| 3555 | y += f->top_pos; | 3661 | item_y = y += f->top_pos; |
| 3556 | 3662 | ||
| 3557 | /* Create all the necessary panes and their items. */ | 3663 | /* Create all the necessary panes and their items. */ |
| 3558 | maxwidth = maxlines = lines = i = 0; | 3664 | maxwidth = maxlines = lines = i = 0; |
| @@ -3710,7 +3816,7 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, | |||
| 3710 | specbind (Qoverriding_terminal_local_map, | 3816 | specbind (Qoverriding_terminal_local_map, |
| 3711 | Fsymbol_value (Qtty_menu_navigation_map)); | 3817 | Fsymbol_value (Qtty_menu_navigation_map)); |
| 3712 | status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap, | 3818 | status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap, |
| 3713 | tty_menu_help_callback); | 3819 | tty_menu_help_callback, kbd_navigation); |
| 3714 | entry = pane_prefix = Qnil; | 3820 | entry = pane_prefix = Qnil; |
| 3715 | 3821 | ||
| 3716 | switch (status) | 3822 | switch (status) |
| @@ -3751,6 +3857,12 @@ tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, | |||
| 3751 | } | 3857 | } |
| 3752 | break; | 3858 | break; |
| 3753 | 3859 | ||
| 3860 | case TTYM_NEXT: | ||
| 3861 | case TTYM_PREV: | ||
| 3862 | tty_menu_new_item_coords (f, status, &item_x, &item_y); | ||
| 3863 | entry = Fcons (make_number (item_x), make_number (item_y)); | ||
| 3864 | break; | ||
| 3865 | |||
| 3754 | case TTYM_FAILURE: | 3866 | case TTYM_FAILURE: |
| 3755 | *error_name = "Can't activate menu"; | 3867 | *error_name = "Can't activate menu"; |
| 3756 | case TTYM_IA_SELECT: | 3868 | case TTYM_IA_SELECT: |