aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2013-10-08 17:28:37 +0300
committerEli Zaretskii2013-10-08 17:28:37 +0300
commit4a48e94d50bad36ed872725db8d8cddbac5a9f47 (patch)
tree2946df7bacbe036ac9fef86e1a3cfcfe1caa94a0 /src
parent493a197846a4483f21605950e6214e42ecb6fc62 (diff)
downloademacs-4a48e94d50bad36ed872725db8d8cddbac5a9f47.tar.gz
emacs-4a48e94d50bad36ed872725db8d8cddbac5a9f47.zip
Horizontal keys in TTY menus work.
Diffstat (limited to 'src')
-rw-r--r--src/menu.c29
-rw-r--r--src/menu.h3
-rw-r--r--src/term.c132
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
1039static int 1039int
1040item_width (const char *str) 1040menu_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
1160no quit occurs and `x-popup-menu' returns nil. */) 1160no 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,
52extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool, 52extern Lisp_Object xmenu_show (struct frame *, int, int, bool, bool,
53 Lisp_Object, const char **, Time); 53 Lisp_Object, const char **, Time);
54extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int, 54extern Lisp_Object tty_menu_show (struct frame *, int, int, int, int,
55 Lisp_Object, const char **); 55 Lisp_Object, int, const char **);
56extern 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. */
2794static const char *menu_help_message, *prev_menu_help_message; 2796static 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. */
3179static int 3182static int
3180read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y, 3183read_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. */
3258int 3267static int
3259tty_menu_activate (tty_menu *menu, int *pane, int *selidx, 3268tty_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. */
3537static int
3538tty_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. */
3566static void
3567tty_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
3512Lisp_Object 3617Lisp_Object
3513tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps, 3618tty_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: