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