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