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