1 static char *SCCS_Id = "@(#)xprompt.c\tver 1.4 (91/09/28 14:23:33) brachman@cs.ubc.ca";
2
3 /* vi: set tabstop=4 : */
4
5 /*
6 * xprompt - prompt the user for one or more replies
7 *
8 *
9 * 28-Sep-91 Convert to X11R5, retain X11R4, lose X11R3
10 * Casey Leedom <casey@gauss.llnl.gov>
11 *
12 * 28-Jan-90 Convert to X11R4, retain X11R3 compatibility
13 *
14 * 11-Mar-89 Fixed problem with XSetInputFocus being done before windows
15 * were viewable.
16 *
17 * 24-Jan-89 Written for X11R3. Released for distribution.
18 *
19 *
20 * Copyright 1989, 1990, 1991, 1995 by
21 * Barry Brachman and the University of British Columbia
22 *
23 * Permission to use, copy, modify, distribute, and sell this software and its
24 * documentation for any purpose is hereby granted without fee, provided that
25 * the above copyright notice appear in all copies and that both that
26 * copyright notice and this permission notice appear in supporting
27 * documentation, and that the name of U.B.C. not be used in advertising or
28 * publicity pertaining to distribution of the software without specific,
29 * written prior permission. U.B.C. makes no representations about the
30 * suitability of this software for any purpose. It is provided "as is"
31 * without express or implied warranty.
32 *
33 * -----
34 * Barry Brachman <brachman@cs.ubc.ca>
35 * Dept. of Computer Science
36 * 2366 Main Mall, Univ. of British Columbia
37 * Vancouver, B.C. V6T 1Z4
38 */
39
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <ctype.h>
43 #include <stdio.h>
44
45 #include <X11/IntrinsicP.h>
46 #include <X11/StringDefs.h>
47 #include <X11/Shell.h>
48 #include <X11/Xaw/Box.h>
49 #include <X11/Xaw/AsciiText.h>
50
51 #include "trexp.h"
52
53 #define maximum(x, y) ((x) > (y) ? (x) : (y))
54
55 #define GEOM_WIDTH_PAD 25 /* Extra padding for window width */
56 #define GEOM_HEIGHT_PAD 15 /* Same for height */
57
58 static XrmOptionDescRec table[] = {
59 {"-grab", "Grab", XrmoptionNoArg, (caddr_t) "on"},
60 {"-ibw", "insideborderWidth", XrmoptionSepArg, NULL},
61 {"-nograb", "Grab", XrmoptionNoArg, (caddr_t) "off"},
62 {"-nowarp", "Warp", XrmoptionNoArg, (caddr_t) "off"},
63 {"-nre", "returnExit", XrmoptionNoArg, (caddr_t) "off"},
64 {"-p", "", XrmoptionSkipLine, NULL},
65 {"-pfn", "promptFont", XrmoptionSepArg, NULL},
66 {"-re", "returnExit", XrmoptionNoArg, (caddr_t) "on"},
67 {"-rfn", "replyFont", XrmoptionSepArg, NULL},
68 {"-rlen", "Rlen", XrmoptionSepArg, NULL},
69 {"-tf", "textTranslationFile", XrmoptionSepArg, NULL},
70 {"-w", "wordChars", XrmoptionSepArg, NULL},
71 {"-warp", "Warp", XrmoptionNoArg, (caddr_t) "on"},
72 };
73
74 typedef struct {
75 int rlen; /* maximum reply length */
76 Boolean grab; /* If TRUE, grab the keyboard */
77 Boolean warp; /* If TRUE, warp to reply window */
78 Boolean return_exit; /* If TRUE, exit on <return> if single prompt */
79 char *texttranslations;
80 char *texttranslationfile;
81 char *wordchars;
82 char *geometry;
83 int borderwidth;
84 int insideborderwidth;
85 XFontStruct *font;
86 XFontStruct *pfont;
87 XFontStruct *rfont;
88 } app_resourceRec, *app_res;
89
90 static app_resourceRec app_resources;
91
92 static XtResource resources[] = {
93 {"rlen", "Rlen", XtRInt, sizeof(int),
94 XtOffset(app_res, rlen), XtRImmediate, (caddr_t) 80},
95 {"grab", "Grab", XtRBoolean, sizeof(Boolean),
96 XtOffset(app_res, grab), XtRImmediate, (caddr_t) TRUE },
97 {"insideborderwidth", "insideborderWidth", XtRInt, sizeof(int),
98 XtOffset(app_res, insideborderwidth), XtRImmediate, (caddr_t) 1},
99 {"replyfont", "replyFont", XtRFontStruct, sizeof(XFontStruct *),
100 XtOffset(app_res, rfont), XtRString, NULL},
101 {"promptfont", "promptFont", XtRFontStruct, sizeof(XFontStruct *),
102 XtOffset(app_res, pfont), XtRString, NULL},
103 {"returnexit", "returnExit", XtRBoolean, sizeof(Boolean),
104 XtOffset(app_res, return_exit), XtRImmediate, (caddr_t) FALSE},
105 {"texttranslationfile", "textTranslationFile", XtRString, sizeof(caddr_t),
106 XtOffset(app_res, texttranslationfile), XtRString, NULL},
107 {"texttranslations", "textTranslations", XtRString, sizeof(caddr_t),
108 XtOffset(app_res, texttranslations), XtRString, NULL},
109 {"wordchars", "wordChars", XtRString, sizeof(caddr_t),
110 XtOffset(app_res, wordchars), XtRString, "a-zA-Z0-9"},
111 {"warp", "Warp", XtRBoolean, sizeof(Boolean),
112 XtOffset(app_res, warp), XtRImmediate, (caddr_t) FALSE },
113
114 {XtNgeometry, "Geometry", XtRString, sizeof(caddr_t),
115 XtOffset(app_res, geometry), XtRString, (caddr_t) "+500+400"},
116 {XtNborderWidth, "borderWidth", XtRInt, sizeof(int),
117 XtOffset(app_res, borderwidth), XtRImmediate, (caddr_t) 1},
118 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
119 XtOffset(app_res, font), XtRString, (caddr_t) XtDefaultFont},
120 };
121
122 static char xprompt_TextTranslations[] =
123 "\
124 Ctrl<Key>C: abort() \n\
125 Ctrl<Key>D: finish-prompt() \n\
126 Ctrl<Key>J: next-prompt() \n\
127 Ctrl<Key>M: next-prompt() \n\
128 <Key>Down: next-prompt() \n\
129 <Key>Up: previous-prompt() \n\
130 <Key>Linefeed: next-prompt() \n\
131 <Key>Return: next-prompt-or-finish() \n\
132 Ctrl<Key>U: erase-line() \n\
133 <Btn1Up>: finish-prompt() \n\
134 <Btn2Up>: finish-prompt() \n\
135 <Btn3Up>: finish-prompt() \n\
136 <Btn1Down>: ignore() \n\
137 <Btn2Down>: ignore() \n\
138 <Btn3Down>: ignore() \n\
139 <Btn1Motion>: ignore() \n\
140 <Btn2Motion>: ignore() \n\
141 <Btn3Motion>: ignore() \n\
142 <VisibilityNotify>: visibility-event() \n\
143 ";
144
145 static struct promptargs {
146 char *prompt;
147 char *reply;
148 Boolean seenprompt;
149 struct promptargs *next;
150 struct promptargs *prev;
151 } *promptargs, *npa, *npa_prev;
152 static int cpromptarg, npromptargs, nprompts_seen;
153
154 static char *promptbuf, *replybuf;
155 static Widget toplevel, box, popup, reply_w, prompt_w;
156 static Widget complete_top_w, complete_w;
157 static Window orig_win;
158 static int orig_x, orig_y;
159 static int reply_x, reply_y;
160 static int prompt_bb_width, prompt_bb_height;
161 static int reply_bb_width, reply_bb_height;
162 static int visible;
163
164 static trexp *word_tr;
165 static void changeprompt(), null_cursor(), string_changed();
166 static void unparsegeometry(), unwarp();
167 static void Syntax();
168 static int get_user_text_translations();
169
170 char *malloc();
171
172 /*ARGSUSED*/
173 static void
EraseLine(ctx,event,args,nargs)174 EraseLine(ctx, event, args, nargs)
175 TextWidget ctx;
176 XEvent event;
177 String *args;
178 Cardinal *nargs;
179 {
180
181 replybuf[0] = '\0';
182 string_changed(reply_w, replybuf, 0);
183 XawTextSetInsertionPoint(reply_w, 0);
184 XawTextDisplay(reply_w);
185 }
186
187 /*ARGSUSED*/
188 static void
EraseWord(ctx,event,args,nargs)189 EraseWord(ctx, event, args, nargs)
190 TextWidget ctx;
191 XEvent event;
192 String *args;
193 Cardinal *nargs;
194 {
195 XawTextPosition endpos, pos, startpos;
196
197 startpos = pos = XawTextGetInsertionPoint(reply_w);
198
199 /* Skip any leading "non-word" characters */
200 while (replybuf[pos] != '\0' && !trexec(word_tr, replybuf[pos]))
201 pos++;
202 /* Skip any "word" characters */
203 while (trexec(word_tr, replybuf[pos]))
204 pos++;
205
206 endpos = pos;
207 pos = startpos;
208 while (replybuf[endpos] != '\0')
209 replybuf[pos++] = replybuf[endpos++];
210 replybuf[pos] = '\0';
211
212 string_changed(reply_w, replybuf, pos);
213 XawTextSetInsertionPoint(reply_w, startpos);
214 XawTextDisplay(reply_w);
215 }
216
217 /*ARGSUSED*/
218 static void
FinishPrompt(w,event,args,nargs)219 FinishPrompt(w, event, args, nargs)
220 Widget w;
221 XEvent event;
222 String *args;
223 Cardinal *nargs;
224 {
225 int i;
226
227 strcpy(npa->reply, replybuf);
228 for (i = 0, npa = promptargs; i < npromptargs; npa = npa->next, i++)
229 printf("%s\n", npa->reply);
230 unwarp();
231 XtDestroyWidget(toplevel);
232 exit(0);
233 }
234
235 /*ARGSUSED*/
236 static void
PreviousPrompt(w,event,args,nargs)237 PreviousPrompt(w, event, args, nargs)
238 Widget w;
239 XEvent event;
240 String *args;
241 Cardinal *nargs;
242 {
243
244 npa_prev = npa;
245 npa = npa->prev;
246 if (--cpromptarg == 0)
247 cpromptarg = npromptargs;
248 changeprompt();
249 }
250
251 /*ARGSUSED*/
252 static void
NextPrompt(w,event,args,nargs)253 NextPrompt(w, event, args, nargs)
254 Widget w;
255 XEvent event;
256 String *args;
257 Cardinal *nargs;
258 {
259
260 if (npromptargs > 1) {
261 npa_prev = npa;
262 npa = npa->next;
263 if (++cpromptarg > npromptargs)
264 cpromptarg = 1;
265 changeprompt();
266 }
267 }
268
269 /*ARGSUSED*/
270 static void
NextPromptOrFinish(w,event,args,nargs)271 NextPromptOrFinish(w, event, args, nargs)
272 Widget w;
273 XEvent event;
274 String *args;
275 Cardinal *nargs;
276 {
277
278 if (nprompts_seen == npromptargs && app_resources.return_exit) {
279 FinishPrompt(w, event, args, nargs);
280 /*NOTREACHED*/
281 }
282 NextPrompt(w, event, args, nargs);
283 }
284
285 /*ARGSUSED*/
286 static void
changeprompt()287 changeprompt()
288 {
289 int replylen, promptlen;
290
291 if (npromptargs > 1)
292 sprintf(promptbuf, "%s[%d/%d]:", npa->prompt, cpromptarg, npromptargs);
293 else
294 sprintf(promptbuf, "%s:", npa->prompt);
295 strcpy(npa_prev->reply, replybuf);
296 strcpy(replybuf, npa->reply);
297 if (npa->seenprompt == FALSE) {
298 npa->seenprompt = TRUE;
299 nprompts_seen++;
300 }
301
302 replylen = strlen(replybuf);
303 promptlen = strlen(promptbuf);
304 string_changed(reply_w, replybuf, replylen);
305 string_changed(prompt_w, promptbuf, promptlen);
306
307 XawTextSetInsertionPoint(reply_w, replylen);
308 XawTextSetInsertionPoint(prompt_w, promptlen);
309
310 XawTextDisplay(reply_w);
311 XawTextDisplay(prompt_w);
312 }
313
314 /*ARGSUSED*/
315 static void
Abort(w,event,args,nargs)316 Abort(w, event, args, nargs)
317 Widget w;
318 XEvent event;
319 String *args;
320 Cardinal *nargs;
321 {
322
323 unwarp();
324 XtDestroyWidget(toplevel);
325 exit(1);
326 }
327
328 /*ARGSUSED*/
329 static void
Ignore(w,event,args,nargs)330 Ignore(w, event, args, nargs)
331 Widget w;
332 XEvent event;
333 String *args;
334 Cardinal *nargs;
335 {
336
337 }
338
339 /*ARGSUSED*/
340 static void
VisibilityEvent(w,event,args,nargs)341 VisibilityEvent(w, event, args, nargs)
342 Widget w;
343 XEvent event;
344 String *args;
345 Cardinal *nargs;
346 {
347
348 visible = 1;
349 }
350
351 static XtActionsRec xprompt_actions[] = {
352 {"erase-line", EraseLine },
353 {"erase-word", EraseWord },
354 {"next-prompt", NextPrompt },
355 {"previous-prompt", PreviousPrompt },
356 {"finish-prompt", FinishPrompt },
357 {"next-prompt-or-finish", NextPromptOrFinish },
358 {"abort", Abort },
359 {"ignore", Ignore },
360 {"visibility-event", VisibilityEvent },
361 };
362
363 static void
Syntax(call)364 Syntax(call)
365 char *call;
366 {
367
368 fprintf(stderr, "%s\n", SCCS_Id);
369 fprintf(stderr, "Usage: %s [flags] [xtoolkitargs] -p prompt [-r reply] \
370 [-p prompt [-r reply]] ...\n", call);
371 fprintf(stderr, "where <flags> is one or more of:\n");
372 fprintf(stderr, "-rlen # (Maximum length of user's reply: default 80)\n");
373 fprintf(stderr, "-ibw # (Border width of inside window: default 1)\n");
374 fprintf(stderr, "-grab (Grab keyboard: default)\n");
375 fprintf(stderr, "-nograb (Don't grab keyboard)\n");
376 fprintf(stderr, "-re (Return key will exit if there's one prompt)\n");
377 fprintf(stderr, "-nre (Return key won't exit: default)\n");
378 fprintf(stderr, "-pfn <font> (Prompt font)\n");
379 fprintf(stderr, "-rfn <font> (Reply font)\n");
380 fprintf(stderr, "-tf <file> (Translation file to override defaults)\n");
381 fprintf(stderr, "-w <str> (Characters making up a word\n");
382 fprintf(stderr, "-warp (Warp cursor to reply window)\n");
383 fprintf(stderr, "-nowarp (Don't warp cursor)\n");
384 exit(1);
385 }
386
387 void unparsegeometry();
388
main(argc,argv)389 main(argc, argv)
390 int argc;
391 char **argv;
392 {
393 register int i, j;
394 int len, maxpromptlen;
395 Arg arg[11];
396 int geom_mask, geom_x, geom_y, geom_width, geom_height;
397 char geom_str[100];
398 XtTranslations t;
399 XFontStruct *prompt_font, *reply_font;
400
401 toplevel = XtInitialize(argv[0], "XPrompt", table, XtNumber(table),
402 &argc, argv);
403
404 XtGetApplicationResources(toplevel, &app_resources, resources,
405 XtNumber(resources), NULL, (Cardinal) 0);
406
407 j = 0;
408 promptargs = NULL;
409 maxpromptlen = 0;
410 for (i = 1; i < argc; i++) {
411 if (i == argc - 1 || strcmp(argv[i], "-p"))
412 Syntax(argv[0]);
413 if (promptargs) {
414 npa->next =
415 (struct promptargs *) malloc(sizeof(struct promptargs));
416 npa->next->prev = npa;
417 npa = npa->next;
418 npa->next = NULL;
419 }
420 else {
421 promptargs = npa =
422 (struct promptargs *) malloc(sizeof(struct promptargs));
423 npa->prev = npa->next = NULL;
424 }
425 npa->prompt = argv[++i];
426 if ((len = strlen(npa->prompt)) > maxpromptlen)
427 maxpromptlen = len;
428 if ((npa->reply = (char *) malloc(app_resources.rlen + 1)) == NULL) {
429 fprintf(stderr, "Can't alloc reply buffer\n");
430 exit(1);
431 }
432 npa->reply[0] = '\0';
433 if (argv[i+1] && !strcmp(argv[i+1], "-r")) {
434 if (++i == argc - 1)
435 Syntax(argv[0]);
436 if (strlen(argv[++i]) > app_resources.rlen) {
437 fprintf(stderr, "xprompt: default reply is too long\n");
438 exit(1);
439 }
440 strcpy(npa->reply, argv[i]);
441 }
442 npa->seenprompt = FALSE;
443 j++;
444 }
445 if ((npromptargs = j) == 0)
446 Syntax(argv[0]);
447 promptargs->prev = npa;
448 npa->next = promptargs;
449 npa = promptargs;
450 cpromptarg = 1;
451 replybuf = (char *) malloc(app_resources.rlen + 1);
452 if (npromptargs > 1) {
453 maxpromptlen += 5;
454 if (npromptargs < 10)
455 maxpromptlen += 2;
456 else if (npromptargs < 100)
457 maxpromptlen += 4;
458 else
459 maxpromptlen += 10; /* yuk */
460 }
461 else
462 maxpromptlen += 2;
463 promptbuf = (char *) malloc(maxpromptlen);
464
465 if (app_resources.pfont == NULL)
466 app_resources.pfont = app_resources.font;
467 if (app_resources.rfont == NULL)
468 app_resources.rfont = app_resources.font;
469
470 XtAddActions(xprompt_actions, XtNumber(xprompt_actions));
471
472 if ((word_tr = trcomp(app_resources.wordchars)) == NULL) {
473 fprintf(stderr, "xprompt: Parse of word chars failed.\n");
474 exit(1);
475 }
476
477 /*
478 * Determine the window geometry
479 */
480 prompt_font = app_resources.pfont;
481 prompt_bb_width = prompt_font->max_bounds.rbearing
482 - prompt_font->min_bounds.lbearing;
483 prompt_bb_height = prompt_font->max_bounds.ascent
484 + prompt_font->max_bounds.descent;
485 reply_font = app_resources.rfont;
486 reply_bb_width = reply_font->max_bounds.rbearing
487 - reply_font->min_bounds.lbearing;
488 reply_bb_height = reply_font->max_bounds.ascent
489 + reply_font->max_bounds.descent;
490
491 geom_x = 500; /* an arbitrary default location */
492 geom_y = 400;
493 geom_width = maxpromptlen * prompt_bb_width
494 + app_resources.rlen * reply_bb_width + GEOM_WIDTH_PAD;
495 geom_height = maximum(prompt_bb_height, reply_bb_height) + GEOM_HEIGHT_PAD;
496 geom_mask =
497 XParseGeometry(app_resources.geometry, &geom_x, &geom_y, &geom_width,
498 &geom_height);
499 if (geom_mask & WidthValue)
500 geom_width *= reply_bb_width;
501 if (geom_mask & HeightValue)
502 geom_height *= reply_bb_height;
503 unparsegeometry(geom_str, geom_mask,
504 geom_width, geom_height,
505 geom_x, geom_y);
506
507 #ifdef DEBUG
508 fprintf(stderr, "prompt_bb_width=%d prompt_bb_height=%d\n",
509 prompt_bb_width, prompt_bb_height);
510 fprintf(stderr, "reply_bb_width=%d reply_bb_height=%d\n",
511 reply_bb_width, reply_bb_height);
512 fprintf(stderr, "geom_width=%d geom_height=%d\n",
513 maxpromptlen * prompt_bb_width
514 + app_resources.rlen * reply_bb_width + GEOM_WIDTH_PAD,
515 maximum(prompt_bb_height, reply_bb_height) + GEOM_HEIGHT_PAD);
516 fprintf(stderr, "geom_mask=%d geom_width=%d geom_height=%d\n",
517 geom_mask, geom_width, geom_height);
518 fprintf(stderr, "%s\n", geom_str);
519 #endif DEBUG
520
521 XtSetArg(arg[0], XtNgeometry, geom_str);
522 XtSetArg(arg[1], XtNborderWidth, app_resources.borderwidth);
523 /*
524 * If you prefer a popup window instead of a managed window, you
525 * can use the overrideShellWidgetClass instead of the
526 * topLevelShellWidgetClass
527 * popup = XtCreatePopupShell("popup", overrideShellWidgetClass,
528 * toplevel, arg, (Cardinal) 2);
529 */
530 popup = XtCreatePopupShell("xprompt", topLevelShellWidgetClass,
531 toplevel, arg, (Cardinal) 2);
532
533 box =
534 XtCreateManagedWidget("box", boxWidgetClass,
535 popup, NULL, (Cardinal) 0);
536
537 if (npromptargs > 1)
538 sprintf(promptbuf, "%s[1/%d]:", promptargs->prompt, npromptargs);
539 else
540 sprintf(promptbuf, "%s:", promptargs->prompt);
541 promptargs->seenprompt = TRUE;
542 nprompts_seen = 1;
543 XtSetArg(arg[0], XtNstring, promptbuf);
544 XtSetArg(arg[1], XtNlength, maxpromptlen);
545 XtSetArg(arg[2], XtNborderWidth, 0);
546 XtSetArg(arg[3], XtNfont, app_resources.pfont);
547 XtSetArg(arg[4], XtNeditType, XawtextRead);
548 XtSetArg(arg[5], XtNwidth, prompt_bb_width * maxpromptlen);
549 XtSetArg(arg[6], XtNsensitive, False);
550 XtSetArg(arg[7], XtNuseStringInPlace, True);
551 XtSetArg(arg[8], XtNdisplayCaret, False);
552 XtSetArg(arg[9], XtNtype, XawAsciiString);
553 prompt_w = XtCreateManagedWidget("text", asciiTextWidgetClass,
554 box, arg, (Cardinal) 10);
555
556 strcpy(replybuf, promptargs->reply);
557 XtSetArg(arg[0], XtNscrollVertical, XawtextScrollWhenNeeded);
558 XtSetArg(arg[1], XtNheight, reply_bb_height + 6);
559 XtSetArg(arg[2], XtNstring, replybuf);
560 XtSetArg(arg[3], XtNlength, app_resources.rlen);
561 XtSetArg(arg[4], XtNeditType, XawtextEdit);
562 XtSetArg(arg[5], XtNborderWidth, app_resources.insideborderwidth);
563 XtSetArg(arg[6], XtNwidth, app_resources.rlen * reply_bb_width);
564 XtSetArg(arg[7], XtNinsertPosition, strlen(promptargs->reply));
565 XtSetArg(arg[8], XtNfont, app_resources.rfont);
566 XtSetArg(arg[9], XtNuseStringInPlace, True);
567 XtSetArg(arg[10], XtNtype, XawAsciiString);
568 reply_w = XtCreateManagedWidget("reply", asciiTextWidgetClass,
569 box, arg, (Cardinal) 11);
570
571 t = XtParseTranslationTable(xprompt_TextTranslations);
572 XtOverrideTranslations(reply_w, t);
573 if (app_resources.texttranslations != NULL) {
574 t = XtParseTranslationTable(app_resources.texttranslations);
575 if (t == NULL) {
576 fprintf(stderr, "xprompt: error parsing translation table.\n");
577 exit(1);
578 }
579 XtOverrideTranslations(reply_w, t);
580 }
581 if (app_resources.texttranslationfile != NULL
582 && get_user_text_translations(app_resources.texttranslationfile) < 0)
583 exit(1);
584
585 visible = 0;
586 XtPopup(popup, XtGrabNonexclusive);
587
588 /*
589 * Handle the grab and/or warp, if necessary
590 */
591 if (app_resources.grab || app_resources.warp) {
592 XWindowAttributes reply_w_attr;
593
594 if (XGetWindowAttributes(XtDisplay(reply_w), XtWindow(reply_w),
595 &reply_w_attr) == 0)
596 app_resources.warp = app_resources.grab = FALSE;
597 else if (!visible) {
598 XEvent event;
599 long em;
600
601 /*
602 * The following weirdness waits for the windows to become visible
603 * before warping the cursor or setting the input focus.
604 * This is necessary to avoid the cases where a window manager
605 * repositions things *after* the warp has occurred and where the
606 * focus window is not viewable at the time of the XSetInputFocus.
607 * Suggestions on the Right Thing welcome.
608 */
609 em = VisibilityChangeMask;
610 XSelectInput(XtDisplay(popup), XtWindow(popup), em);
611 while (1) {
612 bzero(&event, sizeof(event));
613 XNextEvent(XtDisplay(popup), &event);
614 if (event.type == VisibilityNotify)
615 break;
616 }
617 em = reply_w_attr.all_event_masks;
618 XSelectInput(XtDisplay(popup), XtWindow(popup), em);
619 }
620
621 if (app_resources.grab) {
622 XGrabKeyboard(XtDisplay(reply_w), XtWindow(reply_w), False,
623 GrabModeAsync, GrabModeAsync, CurrentTime);
624 XSetInputFocus(XtDisplay(reply_w), XtWindow(reply_w),
625 RevertToPointerRoot, CurrentTime);
626 }
627
628 if (app_resources.warp) {
629 Window root_return, child_return;
630 int root_x_return, root_y_return;
631 int win_x_return, win_y_return;
632 unsigned int mask_return;
633
634 orig_x = -1;
635 orig_y = -1;
636 /*
637 * Find out where the cursor is so that it can be put back
638 * before the program exits.
639 */
640 if (XQueryPointer(XtDisplay(popup), XtWindow(popup),
641 &root_return, &child_return,
642 &root_x_return, &root_y_return,
643 &win_x_return, &win_y_return,
644 &mask_return) != 0) {
645 orig_win = root_return;
646 orig_x = root_x_return;
647 orig_y = root_y_return;
648 }
649 reply_x = reply_w_attr.width - reply_w_attr.width / 10;
650 reply_y = reply_w_attr.height / 2;
651
652 XWarpPointer(XtDisplay(reply_w), None, XtWindow(reply_w),
653 0, 0, 0, 0, reply_x, reply_y);
654 }
655 }
656
657 XtMainLoop();
658 }
659
660 static int
get_user_text_translations(file)661 get_user_text_translations(file)
662 char *file;
663 {
664 char *p;
665 FILE *fp;
666 struct stat statb;
667 XtTranslations t;
668
669 if ((fp = fopen(file, "r")) == NULL) {
670 fprintf(stderr, "xprompt: Can't open translation file '%s'.\n", file);
671 return(-1);
672 }
673 if (fstat(fileno(fp), &statb) < 0) {
674 fprintf(stderr, "xprompt: Can't stat translation file '%s'.\n", file);
675 fclose(fp);
676 return(-1);
677 }
678 if (statb.st_size == 0) {
679 fclose(fp);
680 return(0);
681 }
682 if ((p = (char *) malloc((unsigned) statb.st_size)) == NULL) {
683 fprintf(stderr, "xprompt: Can't malloc translation table.\n");
684 fclose(fp);
685 return(-1);
686 }
687 if (fread(p, statb.st_size, 1, fp) == 0) {
688 fprintf(stderr, "xprompt: error reading translation table.\n");
689 free(p);
690 fclose(fp);
691 return(-1);
692 }
693 fclose(fp);
694 if ((t = XtParseTranslationTable(p)) == NULL) {
695 fprintf(stderr, "xprompt: error parsing translation table.\n");
696 free(p);
697 return(-1);
698 }
699 XtOverrideTranslations(reply_w, t);
700 free(p);
701 return(0);
702 }
703
704 static void
unwarp()705 unwarp()
706 {
707
708 if (app_resources.warp && orig_x != -1 && orig_y != -1) {
709 XWarpPointer(XtDisplay(reply_w), None, orig_win,
710 0, 0, 0, 0, orig_x, orig_y);
711 XFlush(XtDisplay(reply_w));
712 }
713 }
714
715 static void
unparsegeometry(buf,mask,w,h,x,y)716 unparsegeometry(buf, mask, w, h, x, y)
717 char *buf;
718 int mask, w, h, x, y;
719 {
720
721 sprintf(buf, "%dx%d%c%d%c%d",
722 w, h,
723 mask & XNegative ? '-' : '+', x,
724 mask & YNegative ? '-' : '+', y);
725 }
726
727 static void
string_changed(w,buf,pos)728 string_changed(w, buf, pos)
729 Widget w;
730 char *buf;
731 XawTextPosition pos;
732 {
733 Arg args[20];
734
735 XtSetArg(args[0], XtNstring, buf);
736 XtSetValues(w, args, (Cardinal) 1);
737 }
738