(tigetstr): Add dummy definition to make Emacs link again.
[bpt/emacs.git] / src / xmenu.c
CommitLineData
dcfdbac7 1/* X Communication module for terminals which understand the X protocol.
774910eb 2 Copyright (C) 1986, 1988, 1992 Free Software Foundation, Inc.
dcfdbac7
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
774910eb 8the Free Software Foundation; either version 2, or (at your option)
dcfdbac7
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* X pop-up deck-of-cards menu facility for gnuemacs.
21 *
22 * Written by Jon Arnold and Roman Budzianowski
23 * Mods and rewrite by Robert Krawitz
24 *
25 */
26
dcfdbac7
JB
27#ifdef XDEBUG
28#include <stdio.h>
29#endif
30
31/* On 4.3 this loses if it comes after xterm.h. */
32#include <signal.h>
33#include "config.h"
34#include "lisp.h"
7708e9bd 35#include "frame.h"
dcfdbac7 36#include "window.h"
031b0e31 37#include "keyboard.h"
dcfdbac7
JB
38
39/* This may include sys/types.h, and that somehow loses
40 if this is not done before the other system files. */
41#include "xterm.h"
42
43/* Load sys/types.h if not already loaded.
44 In some systems loading it twice is suicidal. */
45#ifndef makedev
46#include <sys/types.h>
47#endif
48
49#include "dispextern.h"
50
51#ifdef HAVE_X11
52#include "../oldXMenu/XMenu.h"
53#else
54#include <X/XMenu.h>
55#endif
56
57#define min(x,y) (((x) < (y)) ? (x) : (y))
58#define max(x,y) (((x) > (y)) ? (x) : (y))
59
60#define NUL 0
61
62#ifndef TRUE
63#define TRUE 1
64#define FALSE 0
65#endif TRUE
66
67#ifdef HAVE_X11
68extern Display *x_current_display;
69#else
70#define ButtonReleaseMask ButtonReleased
71#endif /* not HAVE_X11 */
72
d9dcaf49 73Lisp_Object Qmenu_enable;
dcfdbac7
JB
74Lisp_Object xmenu_show ();
75extern int x_error_handler ();
76
77/*************************************************************/
78
79#if 0
80/* Ignoring the args is easiest. */
81xmenu_quit ()
82{
83 error ("Unknown XMenu error");
84}
85#endif
86
87DEFUN ("x-popup-menu",Fx_popup_menu, Sx_popup_menu, 1, 2, 0,
88 "Pop up a deck-of-cards menu and return user's selection.\n\
088831f6
RS
89POSITION is a position specification. This is either a mouse button event\n\
90or a list ((XOFFSET YOFFSET) WINDOW)\n\
dcfdbac7 91where XOFFSET and YOFFSET are positions in characters from the top left\n\
7708e9bd 92corner of WINDOW's frame. A mouse-event list will serve for this.\n\
dcfdbac7
JB
93This controls the position of the center of the first line\n\
94in the first pane of the menu, not the top left of the menu as a whole.\n\
95\n\
088831f6
RS
96MENU is a specifier for a menu. For the simplest case, MENU is a keymap.\n\
97The menu items come from key bindings that have a menu string as well as\n\
98a definition; actually, the \"definition\" in such a key binding looks like\n\
99\(STRING . REAL-DEFINITION). To give the menu a title, put a string into\n\
100the keymap as a top-level element.\n\n\
101You can also use a list of keymaps as MENU.\n\
102 Then each keymap makes a separate pane.\n\n\
103Alternatively, you can specify a menu of multiple panes\n\
104 with a list of the form\n\
105\(TITLE PANE1 PANE2...), where each pane is a list of form\n\
dcfdbac7 106\(TITLE (LINE ITEM)...). Each line should be a string, and item should\n\
dbc4e1c1 107be the return value for that line (i.e. if it is selected).")
088831f6
RS
108 (position, menu)
109 Lisp_Object position, menu;
dcfdbac7
JB
110{
111 int number_of_panes;
088831f6 112 Lisp_Object XMenu_return, keymap, tem;
dcfdbac7
JB
113 int XMenu_xpos, XMenu_ypos;
114 char **menus;
115 char ***names;
116 Lisp_Object **obj_list;
117 int *items;
118 char *title;
119 char *error_name;
120 Lisp_Object ltitle, selection;
121 int i, j;
7708e9bd 122 FRAME_PTR f;
dcfdbac7
JB
123 Lisp_Object x, y, window;
124
088831f6
RS
125 /* Decode the first argument: find the window and the coordinates. */
126 tem = Fcar (position);
127 if (XTYPE (tem) == Lisp_Cons)
128 {
129 window = Fcar (Fcdr (position));
130 x = Fcar (tem);
131 y = Fcar (Fcdr (tem));
132 }
133 else
134 {
031b0e31
JB
135 tem = EVENT_START (position);
136 window = POSN_WINDOW (tem);
137 tem = POSN_WINDOW_POSN (tem);
088831f6
RS
138 x = Fcar (tem);
139 y = Fcdr (tem);
140 }
774910eb 141 CHECK_LIVE_WINDOW (window, 0);
dcfdbac7
JB
142 CHECK_NUMBER (x, 0);
143 CHECK_NUMBER (y, 0);
088831f6 144
7708e9bd 145 f = XFRAME (WINDOW_FRAME (XWINDOW (window)));
dcfdbac7 146
088831f6
RS
147 XMenu_xpos
148 = FONT_WIDTH (f->display.x->font) * (XINT (x) + XWINDOW (window)->left);
149 XMenu_ypos
150 = FONT_HEIGHT (f->display.x->font) * (XINT (y) + XWINDOW (window)->top);
7708e9bd
JB
151 XMenu_xpos += f->display.x->left_pos;
152 XMenu_ypos += f->display.x->top_pos;
dcfdbac7 153
088831f6
RS
154 keymap = Fkeymapp (menu);
155 tem = Qnil;
156 if (XTYPE (menu) == Lisp_Cons)
157 tem = Fkeymapp (Fcar (menu));
158 if (!NILP (keymap))
159 {
160 /* We were given a keymap. Extract menu info from the keymap. */
161 Lisp_Object prompt;
162 keymap = get_keymap (menu);
163
164 /* Search for a string appearing directly as an element of the keymap.
165 That string is the title of the menu. */
166 prompt = map_prompt (keymap);
167 if (!NILP (prompt))
168 title = (char *) XSTRING (prompt)->data;
169
170 /* Extract the detailed info to make one pane. */
171 number_of_panes = keymap_panes (&obj_list, &menus, &names, &items,
172 &menu, 1);
173 /* The menu title seems to be ignored,
174 so put it in the pane title. */
175 if (menus[0] == 0)
176 menus[0] = title;
177 }
178 else if (!NILP (tem))
dcfdbac7 179 {
088831f6
RS
180 /* We were given a list of keymaps. */
181 Lisp_Object prompt;
182 int nmaps = XFASTINT (Flength (menu));
183 Lisp_Object *maps
184 = (Lisp_Object *) alloca (nmaps * sizeof (Lisp_Object));
185 int i;
186 title = 0;
187
188 /* The first keymap that has a prompt string
189 supplies the menu title. */
190 for (tem = menu, i = 0; XTYPE (tem) == Lisp_Cons; tem = Fcdr (tem))
dcfdbac7 191 {
088831f6
RS
192 maps[i++] = keymap = get_keymap (Fcar (tem));
193
194 prompt = map_prompt (keymap);
195 if (title == 0 && !NILP (prompt))
196 title = (char *) XSTRING (prompt)->data;
dcfdbac7 197 }
088831f6
RS
198
199 /* Extract the detailed info to make one pane. */
200 number_of_panes = keymap_panes (&obj_list, &menus, &names, &items,
201 maps, nmaps);
202 /* The menu title seems to be ignored,
203 so put it in the pane title. */
204 if (menus[0] == 0)
205 menus[0] = title;
206 }
207 else
208 {
209 /* We were given an old-fashioned menu. */
210 ltitle = Fcar (menu);
211 CHECK_STRING (ltitle, 1);
212 title = (char *) XSTRING (ltitle)->data;
213 number_of_panes = list_of_panes (&obj_list, &menus, &names, &items,
214 Fcdr (menu));
215 }
216#ifdef XDEBUG
217 fprintf (stderr, "Panes = %d\n", number_of_panes);
218 for (i = 0; i < number_of_panes; i++)
219 {
220 fprintf (stderr, "Pane %d has lines %d title %s\n",
221 i, items[i], menus[i]);
222 for (j = 0; j < items[i]; j++)
223 fprintf (stderr, " Item %d %s\n", j, names[i][j]);
dcfdbac7
JB
224 }
225#endif
226 BLOCK_INPUT;
c4e5d591
JB
227 {
228 Window root;
229 int root_x, root_y;
230 int dummy_int;
231 unsigned int dummy_uint;
232 Window dummy_window;
233
234 /* Figure out which root window F is on. */
235 XGetGeometry (x_current_display, FRAME_X_WINDOW (f), &root,
236 &dummy_int, &dummy_int, &dummy_uint, &dummy_uint,
237 &dummy_uint, &dummy_uint);
238
239 /* Translate the menu co-ordinates within f to menu co-ordinates
240 on that root window. */
241 if (! XTranslateCoordinates (x_current_display,
242 FRAME_X_WINDOW (f), root,
243 XMenu_xpos, XMenu_ypos, &root_x, &root_y,
244 &dummy_window))
245 /* But XGetGeometry said root was the root window of f's screen! */
246 abort ();
247
248 selection = xmenu_show (root, XMenu_xpos, XMenu_ypos, names, menus,
249 items, number_of_panes, obj_list, title,
250 &error_name);
251 }
dcfdbac7 252 UNBLOCK_INPUT;
088831f6 253 /* fprintf (stderr, "selection = %x\n", selection); */
dcfdbac7
JB
254 if (selection != NUL)
255 { /* selected something */
256 XMenu_return = selection;
257 }
258 else
259 { /* nothing selected */
260 XMenu_return = Qnil;
261 }
262 /* now free up the strings */
088831f6 263 for (i = 0; i < number_of_panes; i++)
dcfdbac7
JB
264 {
265 free (names[i]);
266 free (obj_list[i]);
267 }
268 free (menus);
269 free (obj_list);
270 free (names);
271 free (items);
088831f6 272 /* free (title); */
dcfdbac7
JB
273 if (error_name) error (error_name);
274 return XMenu_return;
275}
276
277struct indices {
278 int pane;
279 int line;
280};
281
282Lisp_Object
283xmenu_show (parent, startx, starty, line_list, pane_list, line_cnt,
284 pane_cnt, item_list, title, error)
285 Window parent;
286 int startx, starty; /* upper left corner position BROKEN */
287 char **line_list[]; /* list of strings for items */
288 char *pane_list[]; /* list of pane titles */
289 char *title;
290 int pane_cnt; /* total number of panes */
291 Lisp_Object *item_list[]; /* All items */
292 int line_cnt[]; /* Lines in each pane */
293 char **error; /* Error returned */
294{
295 XMenu *GXMenu;
296 int last, panes, selidx, lpane, status;
297 int lines, sofar;
298 Lisp_Object entry;
299 /* struct indices *datap, *datap_save; */
300 char *datap;
301 int ulx, uly, width, height;
302 int dispwidth, dispheight;
088831f6
RS
303
304 if (pane_cnt == 0)
305 return 0;
306
dcfdbac7
JB
307 *error = (char *) 0; /* Initialize error pointer to null */
308 GXMenu = XMenuCreate (XDISPLAY parent, "emacs");
309 if (GXMenu == NUL)
310 {
311 *error = "Can't create menu";
312 return (0);
313 }
314
088831f6
RS
315 for (panes = 0, lines = 0; panes < pane_cnt;
316 lines += line_cnt[panes], panes++)
dcfdbac7
JB
317 ;
318 /* datap = (struct indices *) xmalloc (lines * sizeof (struct indices)); */
088831f6 319 /* datap = (char *) xmalloc (lines * sizeof (char));
dcfdbac7
JB
320 datap_save = datap;*/
321
088831f6
RS
322 for (panes = 0, sofar = 0; panes < pane_cnt;
323 sofar += line_cnt[panes], panes++)
dcfdbac7
JB
324 {
325 /* create all the necessary panes */
326 lpane = XMenuAddPane (XDISPLAY GXMenu, pane_list[panes], TRUE);
327 if (lpane == XM_FAILURE)
328 {
329 XMenuDestroy (XDISPLAY GXMenu);
330 *error = "Can't create pane";
331 return (0);
332 }
088831f6 333 for (selidx = 0; selidx < line_cnt[panes]; selidx++)
dcfdbac7
JB
334 {
335 /* add the selection stuff to the menus */
336 /* datap[selidx+sofar].pane = panes;
337 datap[selidx+sofar].line = selidx; */
338 if (XMenuAddSelection (XDISPLAY GXMenu, lpane, 0,
339 line_list[panes][selidx], TRUE)
340 == XM_FAILURE)
341 {
342 XMenuDestroy (XDISPLAY GXMenu);
343 /* free (datap); */
344 *error = "Can't add selection to menu";
345 /* error ("Can't add selection to menu"); */
346 return (0);
347 }
348 }
349 }
350 /* all set and ready to fly */
351 XMenuRecompute (XDISPLAY GXMenu);
352 dispwidth = DisplayWidth (x_current_display, XDefaultScreen (x_current_display));
353 dispheight = DisplayHeight (x_current_display, XDefaultScreen (x_current_display));
354 startx = min (startx, dispwidth);
355 starty = min (starty, dispheight);
356 startx = max (startx, 1);
357 starty = max (starty, 1);
358 XMenuLocate (XDISPLAY GXMenu, 0, 0, startx, starty,
359 &ulx, &uly, &width, &height);
360 if (ulx+width > dispwidth)
361 {
362 startx -= (ulx + width) - dispwidth;
363 ulx = dispwidth - width;
364 }
365 if (uly+height > dispheight)
366 {
367 starty -= (uly + height) - dispheight;
368 uly = dispheight - height;
369 }
370 if (ulx < 0) startx -= ulx;
371 if (uly < 0) starty -= uly;
372
373 XMenuSetFreeze (GXMenu, TRUE);
374 panes = selidx = 0;
375
376 status = XMenuActivate (XDISPLAY GXMenu, &panes, &selidx,
377 startx, starty, ButtonReleaseMask, &datap);
378 switch (status)
379 {
380 case XM_SUCCESS:
381#ifdef XDEBUG
382 fprintf (stderr, "pane= %d line = %d\n", panes, selidx);
383#endif
384 entry = item_list[panes][selidx];
385 break;
386 case XM_FAILURE:
088831f6 387 /* free (datap_save); */
dcfdbac7
JB
388 XMenuDestroy (XDISPLAY GXMenu);
389 *error = "Can't activate menu";
390 /* error ("Can't activate menu"); */
391 case XM_IA_SELECT:
392 case XM_NO_SELECT:
393 entry = Qnil;
394 break;
395 }
396 XMenuDestroy (XDISPLAY GXMenu);
088831f6 397 /* free (datap_save);*/
dcfdbac7
JB
398 return (entry);
399}
400
401syms_of_xmenu ()
402{
d9dcaf49
RS
403 Qmenu_enable = intern ("menu-enable");
404
405 staticpro (&Qmenu_enable);
dcfdbac7
JB
406 defsubr (&Sx_popup_menu);
407}
088831f6
RS
408\f
409/* Construct the vectors that describe a menu
410 and store them in *VECTOR, *PANES, *NAMES and *ITEMS.
411 Each of those four values is a vector indexed by pane number.
412 Return the number of panes.
413
414 KEYMAPS is a vector of keymaps. NMAPS gives the length of KEYMAPS. */
415
416int
417keymap_panes (vector, panes, names, items, keymaps, nmaps)
418 Lisp_Object ***vector; /* RETURN all menu objects */
419 char ***panes; /* RETURN pane names */
420 char ****names; /* RETURN all line names */
421 int **items; /* RETURN number of items per pane */
422 Lisp_Object *keymaps;
423 int nmaps;
424{
425 /* Number of panes we have made. */
426 int p = 0;
427 /* Number of panes we have space for. */
428 int npanes_allocated = nmaps;
429 int mapno;
430
431 if (npanes_allocated < 4)
432 npanes_allocated = 4;
433
434 /* Make space for an estimated number of panes. */
435 *vector = (Lisp_Object **) xmalloc (npanes_allocated * sizeof (Lisp_Object *));
436 *panes = (char **) xmalloc (npanes_allocated * sizeof (char *));
437 *items = (int *) xmalloc (npanes_allocated * sizeof (int));
438 *names = (char ***) xmalloc (npanes_allocated * sizeof (char **));
439
440 /* Loop over the given keymaps, making a pane for each map.
441 But don't make a pane that is empty--ignore that map instead.
442 P is the number of panes we have made so far. */
443 for (mapno = 0; mapno < nmaps; mapno++)
444 single_keymap_panes (keymaps[mapno], panes, vector, names, items,
445 &p, &npanes_allocated, "");
446
447 /* Return the number of panes. */
448 return p;
449}
450
451/* This is a recursive subroutine of the previous function.
452 It handles one keymap, KEYMAP.
453 The other arguments are passed along
454 or point to local variables of the previous function. */
455
456single_keymap_panes (keymap, panes, vector, names, items,
457 p_ptr, npanes_allocated_ptr, pane_name)
458 Lisp_Object keymap;
459 Lisp_Object ***vector; /* RETURN all menu objects */
460 char ***panes; /* RETURN pane names */
461 char ****names; /* RETURN all line names */
462 int **items; /* RETURN number of items per pane */
463 int *p_ptr;
464 int *npanes_allocated_ptr;
465 char *pane_name;
466{
467 int i;
468 Lisp_Object pending_maps;
469 Lisp_Object tail, item, item1, item2, table;
470
471 pending_maps = Qnil;
472
473 /* Make sure we have room for another pane. */
474 if (*p_ptr == *npanes_allocated_ptr)
475 {
476 *npanes_allocated_ptr *= 2;
477
478 *vector
479 = (Lisp_Object **) xrealloc (*vector,
480 *npanes_allocated_ptr * sizeof (Lisp_Object *));
481 *panes
482 = (char **) xrealloc (*panes,
483 *npanes_allocated_ptr * sizeof (char *));
484 *items
485 = (int *) xrealloc (*items,
486 *npanes_allocated_ptr * sizeof (int));
487 *names
488 = (char ***) xrealloc (*names,
489 *npanes_allocated_ptr * sizeof (char **));
490 }
491
492 /* When a menu comes from keymaps, don't give names to the panes. */
493 (*panes)[*p_ptr] = pane_name;
494
495 /* Get the length of the list level of the keymap. */
496 i = XFASTINT (Flength (keymap));
497
ab6ee1a0
RS
498 /* Add in lengths of any arrays. */
499 for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
500 if (XTYPE (XCONS (tail)->car) == Lisp_Vector)
501 i += XVECTOR (XCONS (tail)->car)->size;
088831f6
RS
502
503 /* Create vectors for the names and values of the items in the pane.
504 I is an upper bound for the number of items. */
505 (*vector)[*p_ptr] = (Lisp_Object *) xmalloc (i * sizeof (Lisp_Object));
506 (*names)[*p_ptr] = (char **) xmalloc (i * sizeof (char *));
507
508 /* I is now the index of the next unused slots. */
509 i = 0;
510 for (tail = keymap; XTYPE (tail) == Lisp_Cons; tail = XCONS (tail)->cdr)
511 {
512 /* Look at each key binding, and if it has a menu string,
513 make a menu item from it. */
514 item = XCONS (tail)->car;
515 if (XTYPE (item) == Lisp_Cons)
516 {
517 item1 = XCONS (item)->cdr;
518 if (XTYPE (item1) == Lisp_Cons)
519 {
520 item2 = XCONS (item1)->car;
521 if (XTYPE (item2) == Lisp_String)
522 {
d9dcaf49
RS
523 Lisp_Object def, tem;
524 Lisp_Object enabled;
525
526 def = Fcdr (item1);
527 enabled = Qt;
528 if (XTYPE (def) == Lisp_Symbol)
529 {
530 /* No property, or nil, means enable.
531 Otherwise, enable if value is not nil. */
532 tem = Fget (def, Qmenu_enable);
533 if (!NILP (tem))
534 enabled = Feval (tem);
535 }
536 tem = Fkeymapp (def);
088831f6 537 if (XSTRING (item2)->data[0] == '@' && !NILP (tem))
d9dcaf49 538 pending_maps = Fcons (Fcons (def, item2),
088831f6 539 pending_maps);
d9dcaf49 540 else if (!NILP (enabled))
088831f6
RS
541 {
542 (*names)[*p_ptr][i] = (char *) XSTRING (item2)->data;
543 /* The menu item "value" is the key bound here. */
544 (*vector)[*p_ptr][i] = XCONS (item)->car;
545 i++;
546 }
547 }
548 }
549 }
ab6ee1a0
RS
550 else if (XTYPE (item) == Lisp_Vector)
551 {
552 /* Loop over the char values represented in the vector. */
553 int len = XVECTOR (item)->size;
554 int c;
555 for (c = 0; c < len; c++)
556 {
557 Lisp_Object character;
558 XFASTINT (character) = c;
559 item1 = XVECTOR (item)->contents[c];
560 if (XTYPE (item1) == Lisp_Cons)
561 {
562 item2 = XCONS (item1)->car;
563 if (XTYPE (item2) == Lisp_String)
564 {
565 Lisp_Object tem;
d9dcaf49
RS
566 Lisp_Object def;
567 Lisp_Object enabled;
568
569 def = Fcdr (item1);
570 enabled = Qt;
571 if (XTYPE (def) == Lisp_Symbol)
572 {
573 tem = Fget (def, Qmenu_enable);
574 /* No property, or nil, means enable.
575 Otherwise, enable if value is not nil. */
576 if (!NILP (tem))
577 enabled = Feval (tem);
578 }
579
580 tem = Fkeymapp (def);
ab6ee1a0 581 if (XSTRING (item2)->data[0] == '@' && !NILP (tem))
d9dcaf49 582 pending_maps = Fcons (Fcons (def, item2),
ab6ee1a0 583 pending_maps);
d9dcaf49 584 else if (!NILP (enabled))
ab6ee1a0
RS
585 {
586 (*names)[*p_ptr][i] = (char *) XSTRING (item2)->data;
587 /* The menu item "value" is the key bound here. */
588 (*vector)[*p_ptr][i] = character;
589 i++;
590 }
591 }
592 }
593 }
594 }
088831f6
RS
595 }
596 /* Record the number of items in the pane. */
597 (*items)[*p_ptr] = i;
598
599 /* If we just made an empty pane, get rid of it. */
600 if (i == 0)
601 {
602 free ((*vector)[*p_ptr]);
603 free ((*names)[*p_ptr]);
604 }
605 /* Otherwise, advance past it. */
606 else
607 (*p_ptr)++;
608
609 /* Process now any submenus which want to be panes at this level. */
610 while (!NILP (pending_maps))
611 {
612 Lisp_Object elt;
613 elt = Fcar (pending_maps);
614 single_keymap_panes (Fcar (elt), panes, vector, names, items,
615 p_ptr, npanes_allocated_ptr,
616 /* Add 1 to discard the @. */
617 (char *) XSTRING (XCONS (elt)->cdr)->data + 1);
618 pending_maps = Fcdr (pending_maps);
619 }
620}
621\f
622/* Construct the vectors that describe a menu
623 and store them in *VECTOR, *PANES, *NAMES and *ITEMS.
624 Each of those four values is a vector indexed by pane number.
625 Return the number of panes.
626
627 MENU is the argument that was given to Fx_popup_menu. */
dcfdbac7 628
088831f6 629int
dcfdbac7
JB
630list_of_panes (vector, panes, names, items, menu)
631 Lisp_Object ***vector; /* RETURN all menu objects */
632 char ***panes; /* RETURN pane names */
633 char ****names; /* RETURN all line names */
634 int **items; /* RETURN number of items per pane */
635 Lisp_Object menu;
636{
637 Lisp_Object tail, item, item1;
638 int i;
639
640 if (XTYPE (menu) != Lisp_Cons) menu = wrong_type_argument (Qlistp, menu);
641
088831f6 642 i = XFASTINT (Flength (menu));
dcfdbac7
JB
643
644 *vector = (Lisp_Object **) xmalloc (i * sizeof (Lisp_Object *));
645 *panes = (char **) xmalloc (i * sizeof (char *));
646 *items = (int *) xmalloc (i * sizeof (int));
647 *names = (char ***) xmalloc (i * sizeof (char **));
648
088831f6 649 for (i = 0, tail = menu; !NILP (tail); tail = Fcdr (tail), i++)
dcfdbac7 650 {
088831f6
RS
651 item = Fcdr (Fcar (tail));
652 if (XTYPE (item) != Lisp_Cons) (void) wrong_type_argument (Qlistp, item);
dcfdbac7 653#ifdef XDEBUG
088831f6 654 fprintf (stderr, "list_of_panes check tail, i=%d\n", i);
dcfdbac7 655#endif
088831f6
RS
656 item1 = Fcar (Fcar (tail));
657 CHECK_STRING (item1, 1);
dcfdbac7 658#ifdef XDEBUG
088831f6
RS
659 fprintf (stderr, "list_of_panes check pane, i=%d%s\n", i,
660 XSTRING (item1)->data);
dcfdbac7 661#endif
088831f6
RS
662 (*panes)[i] = (char *) XSTRING (item1)->data;
663 (*items)[i] = list_of_items ((*vector)+i, (*names)+i, item);
664 /* (*panes)[i] = (char *) xmalloc ((XSTRING (item1)->size)+1);
665 bcopy (XSTRING (item1)->data, (*panes)[i], XSTRING (item1)->size + 1)
666 ; */
dcfdbac7
JB
667 }
668 return i;
669}
088831f6
RS
670\f
671/* Construct the lists of values and names for a single pane, from the
672 alist PANE. Put them in *VECTOR and *NAMES.
673 Return the number of items. */
dcfdbac7 674
088831f6 675int
dcfdbac7
JB
676list_of_items (vector, names, pane) /* get list from emacs and put to vector */
677 Lisp_Object **vector; /* RETURN menu "objects" */
678 char ***names; /* RETURN line names */
679 Lisp_Object pane;
680{
681 Lisp_Object tail, item, item1;
682 int i;
683
684 if (XTYPE (pane) != Lisp_Cons) pane = wrong_type_argument (Qlistp, pane);
685
f1b28218 686 i = XFASTINT (Flength (pane));
dcfdbac7
JB
687
688 *vector = (Lisp_Object *) xmalloc (i * sizeof (Lisp_Object));
689 *names = (char **) xmalloc (i * sizeof (char *));
690
088831f6 691 for (i = 0, tail = pane; !NILP (tail); tail = Fcdr (tail), i++)
dcfdbac7 692 {
088831f6
RS
693 item = Fcar (tail);
694 if (XTYPE (item) != Lisp_Cons) (void) wrong_type_argument (Qlistp, item);
dcfdbac7 695#ifdef XDEBUG
088831f6 696 fprintf (stderr, "list_of_items check tail, i=%d\n", i);
dcfdbac7 697#endif
088831f6
RS
698 (*vector)[i] = Fcdr (item);
699 item1 = Fcar (item);
700 CHECK_STRING (item1, 1);
dcfdbac7 701#ifdef XDEBUG
088831f6
RS
702 fprintf (stderr, "list_of_items check item, i=%d%s\n", i,
703 XSTRING (item1)->data);
dcfdbac7 704#endif
088831f6 705 (*names)[i] = (char *) XSTRING (item1)->data;
dcfdbac7
JB
706 }
707 return i;
708}