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