home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / xprompt / part01 / xprompt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-10  |  18.3 KB  |  677 lines

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