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