- /* We were given a list of keymaps. */
- int nmaps = XFASTINT (Flength (menu));
- Lisp_Object *maps
- = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- int i;
-
- title = Qnil;
-
- /* The first keymap that has a prompt string
- supplies the menu title. */
- for (tem = menu, i = 0; XTYPE (tem) == Lisp_Cons; tem = Fcdr (tem))
- {
- Lisp_Object prompt;
-
- maps[i++] = keymap = get_keymap (Fcar (tem));
-#if 0
- prompt = map_prompt (keymap);
- if (NILP (title) && !NILP (prompt))
- title = prompt;
-#endif
- }
-
- /* Extract the detailed info to make one pane. */
- hmenu = keymap_panes (lpmm, maps, nmaps, notreal);
-
-#if 0
- /* Make the title be the pane title of the first pane. */
- if (!NILP (title) && menu_items_n_panes >= 0)
- XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME] = title;
-#endif
- }
- else
- {
- /* We were given an old-fashioned menu. */
- title = Fcar (menu);
- CHECK_STRING (title, 1);
-
- hmenu = list_of_panes (lpmm, Fcdr (menu));
- }
-
- return (hmenu);
-}
-
-/* This is a recursive subroutine of keymap_panes.
- It handles one keymap, KEYMAP.
- The other arguments are passed along
- or point to local variables of the previous function.
- If NOTREAL is nonzero,
- don't bother really computing whether an item is enabled. */
-
-Lisp_Object
-get_single_keymap_event (keymap, lpnum)
- Lisp_Object keymap;
- int * lpnum;
-{
- Lisp_Object pending_maps;
- Lisp_Object tail, item, item1, item_string, table;
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
-
- pending_maps = Qnil;
-
- for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
- {
- /* Look at each key binding, and if it has a menu string,
- make a menu item from it. */
-
- item = XCONS (tail)->car;
-
- if (XTYPE (item) == Lisp_Cons)
- {
- item1 = XCONS (item)->cdr;
-
- if (CONSP (item1))
- {
- item_string = XCONS (item1)->car;
- if (XTYPE (item_string) == Lisp_String)
- {
- /* This is the real definition--the function to run. */
-
- Lisp_Object def;
-
- /* These are the saved equivalent keyboard key sequence
- and its key-description. */
-
- Lisp_Object descrip;
- Lisp_Object tem, enabled;
-
- /* GCPRO because ...enabled_p will call eval
- and ..._equiv_key may autoload something.
- Protecting KEYMAP preserves everything we use;
- aside from that, must protect whatever might be
- a string. Since there's no GCPRO5, we refetch
- item_string instead of protecting it. */
-
- descrip = def = Qnil;
- GCPRO3 (keymap, pending_maps, def);
-
- def = menu_item_equiv_key (item_string, item1, &descrip);
-
- UNGCPRO;
-
- item_string = XCONS (item1)->car;
-
- tem = Fkeymapp (def);
- if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
- {
- pending_maps = Fcons (Fcons (def,
- Fcons (item_string,
- XCONS (item)->car)),
- pending_maps);
- }
- else
- {
- Lisp_Object submap;
-
- GCPRO5 (keymap, pending_maps, item, item_string, descrip);
-
- submap = get_keymap_1 (def, 0, 1);
-
- UNGCPRO;
-
- if (NILP (submap))
- {
- if (--(*lpnum) == 0)
- {
- return (Fcons (XCONS (item)->car, Qnil));
- }
- }
- else
- /* Display a submenu. */
- {
- Lisp_Object event = get_single_keymap_event (submap,
- lpnum);
-
- if (*lpnum <= 0)
- {
- if (!NILP (XCONS (item)->car))
- event = Fcons (XCONS (item)->car, event);
-
- return (event);
- }
- }
- }
- }
- }
- }
- else if (VECTORP (item))
- {
- /* Loop over the char values represented in the vector. */
- int len = XVECTOR (item)->size;
- int c;
- for (c = 0; c < len; c++)
- {
- Lisp_Object character;
- XSETFASTINT (character, c);
- item1 = XVECTOR (item)->contents[c];
- if (XTYPE (item1) == Lisp_Cons)
- {
- item_string = XCONS (item1)->car;
- if (XTYPE (item_string) == Lisp_String)
- {
- Lisp_Object def;
-
- /* These are the saved equivalent keyboard key sequence
- and its key-description. */
- Lisp_Object descrip;
- Lisp_Object tem, enabled;
-
- /* GCPRO because ...enabled_p will call eval
- and ..._equiv_key may autoload something.
- Protecting KEYMAP preserves everything we use;
- aside from that, must protect whatever might be
- a string. Since there's no GCPRO5, we refetch
- item_string instead of protecting it. */
- GCPRO3 (keymap, pending_maps, def);
- descrip = def = Qnil;
-
- def = menu_item_equiv_key (item_string, item1, &descrip);
-
- UNGCPRO;
-
- item_string = XCONS (item1)->car;
-
- tem = Fkeymapp (def);
- if (XSTRING (item_string)->data[0] == '@' && !NILP (tem))
- pending_maps = Fcons (Fcons (def, Fcons (item_string, character)),
- pending_maps);
- else
- {
- Lisp_Object submap;
-
- GCPRO5 (keymap, pending_maps, descrip, item_string, descrip);
-
- submap = get_keymap_1 (def, 0, 1);
-
- UNGCPRO;
-
- if (NILP (submap))
- {
- if (--(*lpnum) == 0)
- {
- return (Fcons (character, Qnil));
- }
- }
- else
- /* Display a submenu. */
- {
- Lisp_Object event = get_single_keymap_event (submap,
- lpnum);
-
- if (*lpnum <= 0)
- {
- if (!NILP (character))
- event = Fcons (character, event);
-
- return (event);
- }
- }
- }
- }
- }
- }
- }
- }
-
- /* Process now any submenus which want to be panes at this level. */
- while (!NILP (pending_maps))
- {
- Lisp_Object elt, eltcdr, string;
- elt = Fcar (pending_maps);
- eltcdr = XCONS (elt)->cdr;
- string = XCONS (eltcdr)->car;
- /* We no longer discard the @ from the beginning of the string here.
- Instead, we do this in w32menu_show. */
- {
- Lisp_Object event = get_single_keymap_event (Fcar (elt), lpnum);
-
- if (*lpnum <= 0)
- {
- if (!NILP (XCONS (eltcdr)->cdr))
- event = Fcons (XCONS (eltcdr)->cdr, event);
-
- return (event);
- }
- }
-
- pending_maps = Fcdr (pending_maps);
- }
-
- return (Qnil);
-}
-
-/* Look through KEYMAPS, a vector of keymaps that is NMAPS long,
- and generate menu panes for them in menu_items.
- If NOTREAL is nonzero,
- don't bother really computing whether an item is enabled. */
-
-static Lisp_Object
-get_keymap_event (keymaps, nmaps, lpnum)
- Lisp_Object *keymaps;
- int nmaps;
- int * lpnum;
-{
- int mapno;
- Lisp_Object event = Qnil;
-
- /* Loop over the given keymaps, making a pane for each map.
- But don't make a pane that is empty--ignore that map instead.
- P is the number of panes we have made so far. */
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- event = get_single_keymap_event (keymaps[mapno], lpnum);
-
- if (*lpnum <= 0) break;
- }
-
- return (event);
-}
-
-static Lisp_Object
-get_list_of_items_event (pane, lpnum)
- Lisp_Object pane;
- int * lpnum;
-{
- Lisp_Object tail, item, item1;
-
- for (tail = pane; !NILP (tail); tail = Fcdr (tail))
- {
- item = Fcar (tail);
- if (STRINGP (item))
- {
- if (-- (*lpnum) == 0)
- {
- return (Qnil);
- }
- }
- else if (!NILP (item))
- {
- if (--(*lpnum) == 0)
- {
- CHECK_CONS (item, 0);
- return (Fcdr (item));
- }
- }
- }
-
- return (Qnil);
-}
-
-/* Push all the panes and items of a menu described by the
- alist-of-alists MENU.
- This handles old-fashioned calls to x-popup-menu. */
-
-static Lisp_Object
-get_list_of_panes_event (menu, lpnum)
- Lisp_Object menu;
- int * lpnum;
-{
- Lisp_Object tail;
-
- for (tail = menu; !NILP (tail); tail = Fcdr (tail))
- {
- Lisp_Object elt, pane_name, pane_data;
- Lisp_Object event;
-
- elt = Fcar (tail);
- pane_data = Fcdr (elt);
- CHECK_CONS (pane_data, 0);
-
- event = get_list_of_items_event (pane_data, lpnum);
-
- if (*lpnum <= 0)
- {
- return (event);
- }
- }
-
- return (Qnil);
-}
-
-Lisp_Object
-get_menu_event (menu, lpnum)
- Lisp_Object menu;
- int * lpnum;
-{
- Lisp_Object keymap, tem;
- Lisp_Object event;
-
- /* Decode the menu items from what was specified. */
-
- keymap = Fkeymapp (menu);
- tem = Qnil;
- if (XTYPE (menu) == Lisp_Cons)
- tem = Fkeymapp (Fcar (menu));
-
- if (!NILP (keymap))
- {
- keymap = get_keymap (menu);
-
- event = get_keymap_event (&keymap, 1, lpnum);
- }
- else if (!NILP (tem))
- {
- /* We were given a list of keymaps. */
- int nmaps = XFASTINT (Flength (menu));
- Lisp_Object *maps
- = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
- int i;
-
- /* The first keymap that has a prompt string
- supplies the menu title. */
- for (tem = menu, i = 0; XTYPE (tem) == Lisp_Cons; tem = Fcdr (tem))
- {
- Lisp_Object prompt;
-
- maps[i++] = keymap = get_keymap (Fcar (tem));
- }
-
- event = get_keymap_event (maps, nmaps, lpnum);
- }
- else
- {
- /* We were given an old-fashioned menu. */
- event = get_list_of_panes_event (Fcdr (menu), lpnum);
- }
-
- return (event);
-}
-
-DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0,
- "Pop up a deck-of-cards menu and return user's selection.\n\
-POSITION is a position specification. This is either a mouse button event\n\
-or a list ((XOFFSET YOFFSET) WINDOW)\n\
-where XOFFSET and YOFFSET are positions in pixels from the top left\n\
-corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.)\n\
-This controls the position of the center of the first line\n\
-in the first pane of the menu, not the top left of the menu as a whole.\n\
-If POSITION is t, it means to use the current mouse position.\n\
-\n\
-MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
-The menu items come from key bindings that have a menu string as well as\n\
-a definition; actually, the \"definition\" in such a key binding looks like\n\
-\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
-the keymap as a top-level element.\n\n\
-You can also use a list of keymaps as MENU.\n\
- Then each keymap makes a separate pane.\n\
-When MENU is a keymap or a list of keymaps, the return value\n\
-is a list of events.\n\n\
-Alternatively, you can specify a menu of multiple panes\n\
- with a list of the form (TITLE PANE1 PANE2...),\n\
-where each pane is a list of form (TITLE ITEM1 ITEM2...).\n\
-Each ITEM is normally a cons cell (STRING . VALUE);\n\
-but a string can appear as an item--that makes a nonselectable line\n\
-in the menu.\n\
-With this form of menu, the return value is VALUE from the chosen item.\n\
-\n\
-If POSITION is nil, don't display the menu at all, just precalculate the\n\
-cached information about equivalent key sequences.")
- (position, menu)
- Lisp_Object position, menu;
-{
- int number_of_panes, panes;
- Lisp_Object keymap, tem;
- int xpos, ypos;
- Lisp_Object title;
- char *error_name;
- Lisp_Object selection;
- int i, j;
- FRAME_PTR f;
- Lisp_Object x, y, window;
- int keymaps = 0;
- int menubarp = 0;
- struct gcpro gcpro1;
- HMENU hmenu;
- menu_map mm;
-
- if (! NILP (position))
- {
- /* Decode the first argument: find the window and the coordinates. */
- if (EQ (position, Qt)
- || (CONSP (position) && EQ (XCONS (position)->car, Qmenu_bar)))