pull-prototypes-to-head-20020821
[openafs.git] / src / gtx / frame.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #define IGNORE_STDS_H
11 #include <afsconfig.h>
12 #include <afs/param.h>
13
14 RCSID("$Header$");
15
16 #ifdef AFS_HPUX_ENV
17 #include <sys/types.h>
18 #endif
19 #include <lwp.h>
20
21 #ifdef HAVE_STRING_H
22 #include <string.h>
23 #else
24 #ifdef HAVE_STRINGS_H
25 #include <strings.h>
26 #endif
27 #endif
28 #include <stdlib.h>
29
30 #include "gtxobjects.h"
31 #include "gtxwindows.h"
32 #include "gtxcurseswin.h"
33 #include "gtxinput.h"
34 #include "gtxkeymap.h"
35 #include "gtxframe.h"
36
37 extern char *gtx_CopyString();
38 static struct keymap_map *recursiveMap=0;
39 static char menubuffer[1024];           /*Buffer for menu selections*/
40 int gtxframe_exitValue = 0;             /*Program exit value*/
41
42 gtxframe_CtrlUCmd(awindow, arock)
43 char *arock;
44 struct gwin *awindow; {
45     struct gtx_frame *tframe;
46
47     tframe = awindow->w_frame;
48     if (!tframe->defaultLine) return -1;
49     *(tframe->defaultLine) = 0;
50     return 0;
51 }
52
53 gtxframe_CtrlHCmd(awindow, arock)
54 char *arock;
55 struct gwin *awindow; {
56     register struct gtx_frame *tframe;
57     register char *tp;
58     register int pos;
59
60     tframe = awindow->w_frame;
61     if (!(tp=tframe->defaultLine)) return -1;
62     pos = strlen(tp);
63     if (pos == 0) return 0;     /* rubout at the end of the line */
64     tp[pos-1] = 0;
65     return 0;
66 }
67
68 gtxframe_RecursiveEndCmd(awindow, arock)
69 char *arock;
70 register struct gwin *awindow; {
71     register struct gtx_frame *tframe;
72
73     tframe = awindow->w_frame;
74     tframe->flags |= GTXFRAME_RECURSIVEEND;
75     tframe->flags &= ~GTXFRAME_RECURSIVEERR;
76     return 0;
77 }
78
79 gtxframe_RecursiveErrCmd(awindow, arock)
80 char *arock;
81 register struct gwin *awindow; {
82     register struct gtx_frame *tframe;
83
84     tframe = awindow->w_frame;
85     tframe->flags |= GTXFRAME_RECURSIVEEND;
86     tframe->flags |= GTXFRAME_RECURSIVEERR;
87     return 0;
88 }
89
90 gtxframe_SelfInsertCmd(awindow, arock)
91 int arock;
92 struct gwin *awindow; {
93     register struct gtx_frame *tframe;
94     register int pos;
95     register char *tp;
96
97     tframe = awindow->w_frame;
98     if (!(tp = tframe->defaultLine)) return -1;
99     pos = strlen(tp);
100     tp[pos] = arock;    /* arock has char to insert */
101     tp[pos+1] = 0;      /* null-terminate it, too */
102     return 0;
103 }
104
105 /* save map, setup recursive map and install it */
106 static SaveMap(aframe)
107 register struct gtx_frame *aframe; {
108     char tstring[2];
109     register int i;
110
111     if (!recursiveMap) {
112         /* setup recursive edit map if not previously done */
113         recursiveMap = keymap_Create();
114         keymap_BindToString(recursiveMap,
115                             "\010",
116                             gtxframe_CtrlHCmd,
117                             NULL,
118                             NULL);
119         keymap_BindToString(recursiveMap,
120                             "\177",gtxframe_CtrlHCmd,
121                             NULL,
122                             NULL);
123         keymap_BindToString(recursiveMap,
124                             "\025",
125                             gtxframe_CtrlUCmd,
126                             NULL,
127                             NULL);
128         keymap_BindToString(recursiveMap,
129                             "\033",
130                             gtxframe_RecursiveEndCmd,
131                             NULL,
132                             NULL);
133         keymap_BindToString(recursiveMap,
134                             "\015",
135                             gtxframe_RecursiveEndCmd,
136                             NULL,
137                             NULL);
138         keymap_BindToString(recursiveMap,
139                             "\012",
140                             gtxframe_RecursiveEndCmd,
141                             NULL,
142                             NULL);
143         keymap_BindToString(recursiveMap,
144                             "\003",
145                             gtxframe_RecursiveErrCmd,
146                             NULL,
147                             NULL);
148         keymap_BindToString(recursiveMap,
149                             "\007",
150                             gtxframe_RecursiveErrCmd,
151                             NULL,
152                             NULL);
153
154         for(i=040; i<0177; i++) {
155             tstring[0] = i;
156             tstring[1] = 0;
157             keymap_BindToString(recursiveMap, tstring, gtxframe_SelfInsertCmd,
158                                 NULL, i);
159         }
160     }
161     aframe->savemap = aframe->keymap;
162     aframe->keymap = recursiveMap;
163     keymap_InitState(aframe->keystate, aframe->keymap);
164     return 0;
165 }
166
167 /* Restore map to previous value */
168 static RestoreMap(aframe)
169 register struct gtx_frame *aframe; {
170     aframe->keymap = aframe->savemap;
171     aframe->savemap = (struct keymap_map *) 0;
172     keymap_InitState(aframe->keystate, aframe->keymap);
173     return 0;
174 }
175
176 gtxframe_SetFrame(awin, aframe)
177 struct gtx_frame *aframe;
178 struct gwin *awin; {
179     if (awin->w_frame) {
180         /* Unthread this frame */
181         awin->w_frame->window = NULL;
182     }
183     awin->w_frame = aframe;
184     aframe->window = awin;      /* Set frame's window ptr */
185     return 0;
186 }
187
188 struct gtx_frame *gtxframe_GetFrame(awin)
189 struct gwin *awin; {
190     return awin->w_frame;
191 }
192
193 /* Add a menu string to display list */
194 gtxframe_AddMenu(aframe, alabel, astring)
195 char *alabel;
196 char *astring;
197 struct gtx_frame *aframe; {
198     register struct gtxframe_menu *tmenu;
199
200     if (aframe->menus)
201       for(tmenu = aframe->menus; tmenu; tmenu = tmenu->next) {
202         if (strcmp(alabel, tmenu->name)==0) break;
203       }
204     else
205       tmenu = (struct gtxframe_menu *)0;
206     if (!tmenu) {
207         /* Handle everything but the command string, which is handled by the
208            common-case code below */
209         tmenu = (struct gtxframe_menu *) malloc(sizeof(*tmenu));
210         if (tmenu == (struct gtxframe_menu *)0)
211           return(-1);
212         memset(tmenu, 0, sizeof(*tmenu));
213         tmenu->next = aframe->menus;
214         aframe->menus = tmenu;
215         tmenu->name = gtx_CopyString(alabel);
216     }
217
218     /*
219       * Common case: redo the string labels.  Note: at this point, tmenu
220       * points to a valid menu.
221       */
222     if (tmenu->cmdString)
223       free(tmenu->cmdString);
224     tmenu->cmdString = gtx_CopyString(astring);
225     return 0;
226 }
227
228 /* Delete a given menu from a frame*/
229 gtxframe_DeleteMenu(aframe, alabel)
230 struct gtx_frame *aframe;
231 char *alabel; {
232     register struct gtxframe_menu *tm, **lm;
233
234     for(lm = &aframe->menus, tm = *lm; tm; lm = &tm->next, tm = *lm) {
235         if (strcmp(alabel, tm->name) == 0) {
236             /* found it, remove and return success */
237             *lm = tm->next;             /* unthread from list */
238             free(tm->name);
239             free(tm->cmdString);
240             free(tm);
241             return(0);
242         }
243     }
244     return(-1); /* failed to find entry to delete */
245 }
246
247 /* Function to remove all known menus */
248 gtxframe_ClearMenus(aframe)
249 struct gtx_frame *aframe; {
250
251     register struct gtxframe_menu *tm, *nm;
252
253     if (aframe->menus != (struct gtxframe_menu *)0) {
254       for(tm=aframe->menus; tm; tm=nm) {
255         nm = tm->next;
256         free(tm->name);
257         free(tm->cmdString);
258         free(tm);
259       }
260     }
261
262     aframe->menus = (struct gtxframe_menu *) 0;
263     return 0;
264 }
265
266 gtxframe_AskForString(aframe, aprompt, adefault, aresult, aresultSize)
267 register struct gtx_frame *aframe;
268 char *aprompt;
269 char *adefault;
270 char *aresult;
271 int aresultSize; {
272     register int code;
273     register char *tp;
274
275     /* Ensure recursive-edit map is initialized */
276     SaveMap(aframe);
277
278     /* Set up display */
279     if (aframe->promptLine)
280         free(aframe->promptLine);
281     if (aframe->defaultLine)
282         free(aframe->defaultLine);
283     aframe->promptLine = gtx_CopyString(aprompt);
284     tp = aframe->defaultLine = (char *) malloc(1024);
285     if (tp == NULL)
286       return(-1);
287     if (adefault)
288         strcpy(tp, adefault);
289     else
290         *tp = 0;
291
292     /* Do recursive edit */
293     gtx_InputServer(aframe->window);
294     tp = aframe->defaultLine;   /* In case command reallocated it */
295
296     /* Back from recursive edit, check out what's happened */
297     if (aframe->flags & GTXFRAME_RECURSIVEERR) {
298         code = -1;
299         goto done;
300     }
301     code = strlen(tp);
302     if (code+1 > aresultSize) {
303         code = -2;
304         goto done;
305     }
306     strcpy(aresult, tp);
307     code = 0;
308
309     /* Fall through to cleanup and return code */
310   done:
311     RestoreMap(aframe);
312     if (aframe->promptLine)
313         free(aframe->promptLine);
314     if (aframe->defaultLine)
315         free(aframe->defaultLine);
316     aframe->defaultLine = aframe->promptLine = NULL;
317     if (code)
318         gtxframe_DisplayString(aframe, "[Aborted]");
319     return(code);
320 }
321
322 gtxframe_DisplayString(aframe, amsgLine)
323 char *amsgLine;
324 register struct gtx_frame *aframe; {
325     if (aframe->messageLine)
326       free(aframe->messageLine);
327     aframe->messageLine = gtx_CopyString(amsgLine);
328 }
329
330 /* Called by input processor to try to clear the dude */
331 gtxframe_ClearMessageLine(aframe)
332 struct gtx_frame *aframe; {
333     /* If we haven't shown message long enough yet, just return */
334     if (aframe->flags & GTXFRAME_NEWDISPLAY)
335       return(0);
336     if (aframe->messageLine)
337         free(aframe->messageLine);
338     aframe->messageLine = NULL;
339     return(0);
340 }
341
342 static ShowMessageLine(aframe)
343 struct gtx_frame *aframe; {
344     struct gwin_strparams strparms;
345     struct gwin_sizeparams sizeparms;
346     register char *tp;
347
348     if (!aframe->window) return -1;
349
350     /* First, find window size */
351     WOP_GETDIMENSIONS(aframe->window, &sizeparms);
352
353     if (aframe->promptLine) {
354         memset(&strparms, 0, sizeof(strparms));
355         strparms.x = 0;
356         strparms.y = sizeparms.maxy-1;
357         strparms.highlight = 1;
358         tp = strparms.s = (char *) malloc(1024);
359         strcpy(tp, aframe->promptLine);
360         strcat(tp, aframe->defaultLine);
361         WOP_DRAWSTRING(aframe->window, &strparms);
362         aframe->flags |= GTXFRAME_NEWDISPLAY;
363     }
364     else if (aframe->messageLine) {
365         /* Otherwise we're visible, print the message at the bottom */
366         memset(&strparms, 0, sizeof(strparms));
367         strparms.highlight = 1;
368         strparms.x = 0;
369         strparms.y = sizeparms.maxy-1;
370         strparms.s = aframe->messageLine;
371         WOP_DRAWSTRING(aframe->window, &strparms);
372         aframe->flags |= GTXFRAME_NEWDISPLAY;
373     }
374     return(0);
375 }
376
377 /* Exit function, returning whatever has been put in its argument */
378 int gtxframe_ExitCmd(a_exitValuep)
379     char *a_exitValuep;
380
381 { /*gtxframe_ExitCmd*/
382
383     int exitval;        /*Value we've been asked to exit with*/
384
385     /* This next call should be type independent! */
386     gator_cursesgwin_cleanup(&gator_basegwin);
387
388     exitval = *((int *)(a_exitValuep));
389     exit(exitval);
390
391 } /*gtxframe_ExitCmd*/
392
393 struct gtx_frame *gtxframe_Create() {
394     struct gtx_frame *tframe;
395     struct keymap_map *newkeymap;
396     struct keymap_state *newkeystate;
397
398     /*
399       * Allocate all the pieces first: frame, keymap, and key state.
400       */
401     tframe = (struct gtx_frame *) malloc (sizeof(struct gtx_frame));
402     if (tframe == (struct gtx_frame *)0) {
403       return((struct gtx_frame *)0);
404     }
405
406     newkeymap = keymap_Create();
407     if (newkeymap == (struct keymap_map *)0) {
408       /*
409         * Get rid of the frame before exiting.
410         */
411       free(tframe);
412       return((struct gtx_frame *)0);
413     }
414
415     newkeystate = (struct keymap_state *)
416       malloc(sizeof(struct keymap_state));
417     if (newkeystate == (struct keymap_state *)0) {
418       /*
419         * Get rid of the frame AND the keymap before exiting.
420         */
421       free(tframe);
422       free(newkeymap);
423       return((struct gtx_frame *)0);
424     }
425
426     /*
427       * Now that all the pieces exist, fill them in and stick them in
428       * the right places.
429       */
430     memset(tframe, 0, sizeof(struct gtx_frame));
431     tframe->keymap   = newkeymap;
432     tframe->keystate = newkeystate;
433     keymap_InitState(tframe->keystate, tframe->keymap);
434     keymap_BindToString(tframe->keymap,
435                         "\003",
436                         gtxframe_ExitCmd,
437                         "ExitCmd",
438                         (char *) (&gtxframe_exitValue));
439
440     /*
441       * At this point, we return successfully.
442       */
443     return(tframe);
444 }
445
446 gtxframe_Delete(aframe)
447 register struct gtx_frame *aframe; {
448     keymap_Delete(aframe->keymap);
449     free(aframe->keystate);
450     if (aframe->messageLine)
451       free(aframe->messageLine);
452     free(aframe);
453     return 0;
454 }
455
456 gtxframe_Display(aframe, awm)
457 struct gwin *awm;
458 register struct gtx_frame *aframe; {
459     register struct gtxframe_dlist *tlist;
460     register struct gtxframe_menu *tm;
461     struct gwin_strparams strparms;
462
463     /* Run through the menus, displaying them on the top line */
464     *menubuffer = 0;
465     for(tm = aframe->menus; tm; tm = tm->next) {
466         strcat(menubuffer, tm->name);
467         strcat(menubuffer, ":");
468         strcat(menubuffer, tm->cmdString);
469         strcat(menubuffer, " ");
470     }
471     if (menubuffer[0] != 0) {
472       memset(&strparms, 0, sizeof(strparms));
473       strparms.x = 0;
474       strparms.y = 0;
475       strparms.s = menubuffer;
476       strparms.highlight = 1;
477       WOP_DRAWSTRING(awm, &strparms);
478     }
479
480     /* Run through the display list, displaying all objects */
481     for(tlist=aframe->display; tlist; tlist=tlist->next) {
482         OOP_DISPLAY(((struct onode *)(tlist->data)));
483     }
484
485     /* Finally, show the message line */
486     ShowMessageLine(awm->w_frame);
487     return(0);
488 }
489
490 /* Add an object to a window's display list */
491 gtxframe_AddToList(aframe, aobj)
492 struct onode *aobj;
493 register struct gtx_frame *aframe; {
494     register struct gtxframe_dlist *tlist;
495
496     for(tlist = aframe->display; tlist; tlist=tlist->next) {
497         if (tlist->data == (char *) aobj) {
498           /*
499             * Don't add the same thing twice.
500             */
501           return(-1);
502         }
503     }
504
505     /*
506       * OK, it's not alreadyt there.  Create a new list object, fill it
507       * in, and splice it on.
508       */
509     tlist = (struct gtxframe_dlist *) malloc(sizeof(struct gtxframe_dlist));
510     if (tlist == (struct gtxframe_dlist *)0)
511       return(-1);
512     tlist->data = (char *) aobj;
513     tlist->next = aframe->display;
514     aframe->display = tlist;
515     return(0);
516 }
517
518 /* Remove an object from a display list, if it is already there */
519 gtxframe_RemoveFromList(aframe, aobj)
520 struct onode *aobj;
521 register struct gtx_frame *aframe; {
522     register struct gtxframe_dlist *tlist, **plist;
523     
524     plist = &aframe->display;
525     for(tlist = *plist; tlist; plist = &tlist->next, tlist = *plist) {
526         if (tlist->data == (char *) aobj) {
527             *plist = tlist->next;
528             free(tlist);
529             return 0;
530         }
531     }
532     return(-1); /* Item not found */
533 }
534
535 /* Clear out everything on the display list for the given frame*/
536 gtxframe_ClearList(aframe)
537 register struct gtx_frame *aframe; {
538     register struct gtxframe_dlist *tlist, *nlist;
539
540     if (aframe->display != (struct gtxframe_dlist *)0) {
541       /*
542         * Throw away each display list structure (we have at least
543         * one).
544         */
545       for(tlist = aframe->display; tlist; tlist = nlist) {
546         nlist = tlist->next;
547         free(tlist);
548       }
549     }
550
551     aframe->display = (struct gtxframe_dlist *) 0;
552     return 0;
553 }