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