+/* Return the zero-based index of the last menu-bar item on frame F. */
+static int
+tty_menu_last_menubar_item (struct frame *f)
+{
+ int i = 0;
+
+ eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
+ if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
+ {
+ Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
+
+ while (i < ASIZE (items))
+ {
+ Lisp_Object str;
+
+ str = AREF (items, i + 1);
+ if (NILP (str))
+ break;
+ i += 4;
+ }
+ i -= 4; /* went one too far */
+ }
+ return i;
+}
+
+/* Find in frame F's menu bar the menu item that is next or previous
+ to the item at X/Y, and return that item's position in X/Y. WHICH
+ says which one--next or previous--item to look for. X and Y are
+ measured in character cells. This should only be called on TTY
+ frames. */
+static void
+tty_menu_new_item_coords (struct frame *f, int which, int *x, int *y)
+{
+ eassert (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f));
+ if (FRAME_TERMCAP_P (f) && FRAME_LIVE_P (f))
+ {
+ Lisp_Object items = FRAME_MENU_BAR_ITEMS (f);
+ int last_i = tty_menu_last_menubar_item (f);
+ int i, prev_x;
+
+ /* This loop assumes a single menu-bar line, and will fail to
+ find an item if it is not in the first line. Note that
+ make_lispy_event in keyboard.c makes the same assumption. */
+ for (i = 0, prev_x = -1; i < ASIZE (items); i += 4)
+ {
+ Lisp_Object pos, str;
+ int ix;
+
+ str = AREF (items, i + 1);
+ pos = AREF (items, i + 3);
+ if (NILP (str))
+ return;
+ ix = XINT (pos);
+ if (ix <= *x
+ /* We use <= so the blank between 2 items on a TTY is
+ considered part of the previous item. */
+ && *x <= ix + menu_item_width (SDATA (str)))
+ {
+ /* Found current item. Now compute the X coordinate of
+ the previous or next item. */
+ if (which == TTYM_NEXT)
+ {
+ if (i < last_i)
+ *x = XINT (AREF (items, i + 4 + 3));
+ else
+ *x = 0; /* wrap around to the first item */
+ }
+ else if (prev_x < 0)
+ {
+ /* Wrap around to the last item. */
+ *x = XINT (AREF (items, last_i + 3));
+ }
+ else
+ *x = prev_x;
+ return;
+ }
+ prev_x = ix;
+ }
+ }
+}
+