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