home *** CD-ROM | disk | FTP | other *** search
- /* vi: set tabstop=4 : */
-
- /*
- * xprompt - prompt the user for one or more replies
- *
- * Written for X11R3
- * 24-Jan-89 bjb
- *
- * Copyright (C) 1989 Barry Brachman and The University of British Columbia
- *
- * Permission is given to freely copy and distribute this software provided:
- *
- * 1) You do not sell it,
- * 2) You do not use it for commercial advantage, and
- * 3) This notice accompanies the distribution
- *
- * Barry Brachman | UUCP: {alberta,uw-beaver,uunet}!
- * Dept. of Computer Science| ubc-vision!ubc-csgrads!brachman
- * Univ. of British Columbia| Internet: brachman@cs.ubc.ca
- * Vancouver, B.C. V6T 1W5 | brachman%ubc.csnet@csnet-relay.arpa
- * (604) 228-4327 | brachman@ubc.csnet
- */
-
- #include <X11/Xos.h>
- #include <sys/stat.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <X11/Xatom.h>
- #include <X11/IntrinsicP.h>
- #include <X11/StringDefs.h>
- #include <X11/Box.h>
- #include <X11/Shell.h>
- #include <X11/AsciiText.h>
- #include <X11/TextP.h>
- #include <X11/Cardinals.h>
- #include <X11/Xutil.h>
- #include <X11/Xlib.h>
-
- #include "trexp.h"
-
- #ifndef lint
- static char *version = "xprompt v1.0 brachman@cs.ubc.ca 14-Feb-89";
- #endif lint
-
- static XrmOptionDescRec table[] = {
- {"-grab", "Grab", XrmoptionNoArg, (caddr_t) "on"},
- {"-ibw", "insideborderWidth", XrmoptionSepArg, NULL},
- {"-nograb", "Grab", XrmoptionNoArg, (caddr_t) "off"},
- {"-nowarp", "Warp", XrmoptionNoArg, (caddr_t) "off"},
- {"-nre", "returnExit", XrmoptionNoArg, (caddr_t) "off"},
- {"-p", "", XrmoptionSkipLine, NULL},
- {"-pfn", "promptFont", XrmoptionSepArg, NULL},
- {"-re", "returnExit", XrmoptionNoArg, (caddr_t) "on"},
- {"-rfn", "replyFont", XrmoptionSepArg, NULL},
- {"-rlen", "Rlen", XrmoptionSepArg, NULL},
- {"-tf", "textTranslationFile", XrmoptionSepArg, NULL},
- {"-w", "wordChars", XrmoptionSepArg, NULL},
- {"-warp", "Warp", XrmoptionNoArg, (caddr_t) "on"},
- };
-
- typedef struct {
- int rlen; /* maximum reply length */
- Boolean grab; /* If TRUE, grab the keyboard */
- Boolean warp; /* If TRUE, warp to reply window */
- Boolean return_exit; /* If TRUE, exit on <return> if single prompt */
- char *texttranslations;
- char *texttranslationfile;
- char *wordchars;
- char *geometry;
- int borderwidth;
- int insideborderwidth;
- XFontStruct *font;
- XFontStruct *pfont;
- XFontStruct *rfont;
- } app_resourceRec, *app_res;
-
- static app_resourceRec app_resources;
-
- static XtResource resources[] = {
- {"rlen", "Rlen", XtRInt, sizeof(int),
- XtOffset(app_res, rlen), XtRImmediate, (caddr_t) 80},
- {"grab", "Grab", XtRBoolean, sizeof(Boolean),
- XtOffset(app_res, grab), XtRImmediate, (caddr_t) TRUE },
- {"insideborderwidth", "insideborderWidth", XtRInt, sizeof(int),
- XtOffset(app_res, insideborderwidth), XtRImmediate, (caddr_t) 1},
- {"replyfont", "replyFont", XtRFontStruct, sizeof(XFontStruct *),
- XtOffset(app_res, rfont), XtRString, NULL},
- {"promptfont", "promptFont", XtRFontStruct, sizeof(XFontStruct *),
- XtOffset(app_res, pfont), XtRString, NULL},
- {"returnexit", "returnExit", XtRBoolean, sizeof(Boolean),
- XtOffset(app_res, return_exit), XtRImmediate, (caddr_t) FALSE},
- {"texttranslationfile", "textTranslationFile", XtRString, sizeof(caddr_t),
- XtOffset(app_res, texttranslationfile), XtRString, NULL},
- {"texttranslations", "textTranslations", XtRString, sizeof(caddr_t),
- XtOffset(app_res, texttranslations), XtRString, NULL},
- {"wordchars", "wordChars", XtRString, sizeof(caddr_t),
- XtOffset(app_res, wordchars), XtRString, "a-zA-Z0-9"},
- {"warp", "Warp", XtRBoolean, sizeof(Boolean),
- XtOffset(app_res, warp), XtRImmediate, (caddr_t) FALSE },
-
- {XtNgeometry, "Geometry", XtRString, sizeof(caddr_t),
- XtOffset(app_res, geometry), XtRString, (caddr_t) "500x150+500+400"},
- {XtNborderWidth, "borderWidth", XtRInt, sizeof(int),
- XtOffset(app_res, borderwidth), XtRImmediate, (caddr_t) 1},
- {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
- XtOffset(app_res, font), XtRString, (caddr_t) XtDefaultFont},
- };
-
- static char xprompt_TextTranslations[] =
- "\
- Ctrl<Key>C: abort() \n\
- Ctrl<Key>D: finish-prompt() \n\
- Ctrl<Key>J: next-prompt() \n\
- Ctrl<Key>M: next-prompt() \n\
- <Key>Down: next-prompt() \n\
- <Key>Up: previous-prompt() \n\
- <Key>Linefeed: next-prompt() \n\
- <Key>Return: next-prompt-or-finish() \n\
- Ctrl<Key>U: erase-line() \n\
- <Btn1Up>: finish-prompt() \n\
- <Btn2Up>: finish-prompt() \n\
- <Btn3Up>: finish-prompt() \n\
- <Btn1Down>: ignore() \n\
- <Btn2Down>: ignore() \n\
- <Btn3Down>: ignore() \n\
- <Btn1Motion>: ignore() \n\
- <Btn2Motion>: ignore() \n\
- <Btn3Motion>: ignore() \n\
- <VisibilityNotify>: visibility-event() \n\
- ";
-
- static struct promptargs {
- char *prompt;
- char *reply;
- Boolean seenprompt;
- struct promptargs *next;
- struct promptargs *prev;
- } *promptargs, *npa, *npa_prev;
- static int cpromptarg, npromptargs, nprompts_seen;
-
- static char *promptbuf, *replybuf;
- static Widget toplevel, box, popup, reply_w, prompt_w;
- static Widget complete_top_w, complete_w;
- static Window orig_win;
- static int orig_x, orig_y;
- static int reply_x, reply_y;
- static int bb_width, bb_height;
- static int visible;
-
- static trexp *word_tr;
- static void changeprompt(), unparsegeometry(), unwarp();
- static int get_user_text_translations();
-
- char *malloc();
-
- null_cursor()
- {}
-
- /*ARGSUSED*/
- static void
- EraseLine(ctx, event, args, nargs)
- TextWidget ctx;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- replybuf[0] = '\0';
- XtTextSetLastPos(reply_w, 0);
- XtTextSetInsertionPoint(reply_w, 0);
- XtTextDisplay(reply_w);
- }
-
- /*ARGSUSED*/
- static void
- EraseWord(ctx, event, args, nargs)
- TextWidget ctx;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
- register int endpos, pos, startpos;
-
- startpos = pos = XtTextGetInsertionPoint(reply_w);
-
- /* Skip any leading "non-word" characters */
- while (replybuf[pos] != '\0' && !trexec(word_tr, replybuf[pos]))
- pos++;
- /* Skip any "word" characters */
- while (trexec(word_tr, replybuf[pos]))
- pos++;
-
- endpos = pos;
- pos = startpos;
- while (replybuf[endpos] != '\0')
- replybuf[pos++] = replybuf[endpos++];
- replybuf[pos] = '\0';
-
- XtTextSetLastPos(reply_w, pos);
- XtTextSetInsertionPoint(reply_w, startpos);
- XtTextDisplay(reply_w);
- }
-
- /*ARGSUSED*/
- static void
- FinishPrompt(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
- int i;
-
- strcpy(npa->reply, replybuf);
- for (i = 0, npa = promptargs; i < npromptargs; npa = npa->next, i++)
- printf("%s\n", npa->reply);
- unwarp();
- XtDestroyWidget(toplevel);
- exit(0);
- }
-
- /*ARGSUSED*/
- static void
- PreviousPrompt(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- npa_prev = npa;
- npa = npa->prev;
- if (--cpromptarg == 0)
- cpromptarg = npromptargs;
- changeprompt();
- }
-
- /*ARGSUSED*/
- static void
- NextPrompt(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- if (npromptargs > 1) {
- npa_prev = npa;
- npa = npa->next;
- if (++cpromptarg > npromptargs)
- cpromptarg = 1;
- changeprompt();
- }
- }
-
- /*ARGSUSED*/
- static void
- NextPromptOrFinish(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- if (nprompts_seen == npromptargs && app_resources.return_exit) {
- FinishPrompt(w, event, args, nargs);
- /*NOTREACHED*/
- }
- NextPrompt(w, event, args, nargs);
- }
-
- /*ARGSUSED*/
- static void
- changeprompt()
- {
- int replylen, promptlen;
-
- if (npromptargs > 1)
- sprintf(promptbuf, "%s[%d/%d]:", npa->prompt, cpromptarg, npromptargs);
- else
- sprintf(promptbuf, "%s:", npa->prompt);
- strcpy(npa_prev->reply, replybuf);
- strcpy(replybuf, npa->reply);
- if (npa->seenprompt == FALSE) {
- npa->seenprompt = TRUE;
- nprompts_seen++;
- }
-
- replylen = strlen(replybuf);
- promptlen = strlen(promptbuf);
- XtTextSetLastPos(reply_w, replylen);
- XtTextSetLastPos(prompt_w, promptlen);
-
- XtTextSetInsertionPoint(reply_w, replylen);
- XtTextSetInsertionPoint(prompt_w, promptlen);
-
- XtTextDisplay(reply_w);
- XtTextDisplay(prompt_w);
- }
-
- /*ARGSUSED*/
- static void
- Abort(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- unwarp();
- XtDestroyWidget(toplevel);
- exit(1);
- }
-
- /*ARGSUSED*/
- static void
- Ignore(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- }
-
- /*ARGSUSED*/
- static void
- VisibilityEvent(w, event, args, nargs)
- Widget w;
- XEvent event;
- String *args;
- Cardinal *nargs;
- {
-
- visible = 1;
- }
-
- static XtActionsRec xprompt_actions[] = {
- {"erase-line", EraseLine },
- {"erase-word", EraseWord },
- {"next-prompt", NextPrompt },
- {"previous-prompt", PreviousPrompt },
- {"finish-prompt", FinishPrompt },
- {"next-prompt-or-finish", NextPromptOrFinish },
- {"abort", Abort },
- {"ignore", Ignore },
- {"visibility-event", VisibilityEvent },
- };
-
- static
- Syntax(call)
- char *call;
- {
-
- fprintf(stderr, "Usage: %s [flags] [xtoolkitargs] -p prompt [-r reply] \
- [-p prompt [-r reply]] ...\n", call);
- fprintf(stderr, "where <flags> is one or more of:\n");
- fprintf(stderr, "-rlen # (Maximum length of user's reply: default 80)\n");
- fprintf(stderr, "-ibw # (Border width of inside window: default 1)\n");
- fprintf(stderr, "-grab (Grab keyboard: default)\n");
- fprintf(stderr, "-nograb (Don't grab keyboard)\n");
- fprintf(stderr, "-re (Return key will exit if there's one prompt)\n");
- fprintf(stderr, "-nre (Return key won't exit: default)\n");
- fprintf(stderr, "-pfn <font> (Prompt font)\n");
- fprintf(stderr, "-rfn <font> (Reply font)\n");
- fprintf(stderr, "-tf <file> (Translation file to override defaults)\n");
- fprintf(stderr, "-w <str> (Characters making up a word\n");
- fprintf(stderr, "-warp (Warp cursor to reply window)\n");
- fprintf(stderr, "-nowarp (Don't warp cursor)\n");
- exit(1);
- }
-
- void unparsegeometry();
-
- main(argc, argv)
- unsigned int argc;
- char **argv;
- {
- register int i, j;
- int len, maxpromptlen;
- TextWidget ctx;
- Arg arg[10];
- int geom_mask, geom_x, geom_y, geom_width, geom_height;
- char geom_str[100];
- XtTranslations t;
- XFontStruct *font;
-
- toplevel = XtInitialize(argv[0], "XPrompt", table, XtNumber(table),
- &argc, argv);
-
- XtGetApplicationResources(toplevel, &app_resources, resources,
- XtNumber(resources), NULL, 0);
-
- j = 0;
- promptargs = NULL;
- maxpromptlen = 0;
- for (i = 1; i < argc; i++) {
- if (i == argc - 1 || strcmp(argv[i], "-p"))
- Syntax(argv[0]);
- if (promptargs) {
- npa->next =
- (struct promptargs *) malloc(sizeof(struct promptargs));
- npa->next->prev = npa;
- npa = npa->next;
- npa->next = NULL;
- }
- else {
- promptargs = npa =
- (struct promptargs *) malloc(sizeof(struct promptargs));
- npa->prev = npa->next = NULL;
- }
- npa->prompt = argv[++i];
- if ((len = strlen(npa->prompt)) > maxpromptlen)
- maxpromptlen = len;
- if ((npa->reply = (char *) malloc(app_resources.rlen + 1)) == NULL) {
- fprintf(stderr, "Can't alloc reply buffer\n");
- exit(1);
- }
- npa->reply[0] = '\0';
- if (argv[i+1] && !strcmp(argv[i+1], "-r")) {
- if (++i == argc - 1)
- Syntax(argv[0]);
- if (strlen(argv[++i]) > app_resources.rlen) {
- fprintf(stderr, "xprompt: default reply is too long\n");
- exit(1);
- }
- strcpy(npa->reply, argv[i]);
- }
- npa->seenprompt = FALSE;
- j++;
- }
- if ((npromptargs = j) == 0)
- Syntax(argv[0]);
- promptargs->prev = npa;
- npa->next = promptargs;
- npa = promptargs;
- cpromptarg = 1;
- replybuf = (char *) malloc(app_resources.rlen + 1);
- if (npromptargs > 1) {
- maxpromptlen += 5;
- if (npromptargs < 10)
- maxpromptlen += 2;
- else if (npromptargs < 100)
- maxpromptlen += 4;
- else
- maxpromptlen += 10; /* yuk */
- }
- else
- maxpromptlen += 2;
- promptbuf = (char *) malloc(maxpromptlen);
-
- if (app_resources.pfont == NULL)
- app_resources.pfont = app_resources.font;
- if (app_resources.rfont == NULL)
- app_resources.rfont = app_resources.font;
-
- XtAddActions(xprompt_actions, XtNumber(xprompt_actions));
-
- if ((word_tr = trcomp(app_resources.wordchars)) == NULL) {
- fprintf(stderr, "xprompt: Parse of word chars failed.\n");
- exit(1);
- }
-
- geom_x = 500;
- geom_y = 400;
- geom_width = 800;
- geom_height = 30;
- geom_mask =
- XParseGeometry(app_resources.geometry, &geom_x, &geom_y, &geom_width,
- &geom_height);
- unparsegeometry(geom_str, geom_mask, geom_width, geom_height, geom_x,
- geom_y);
- XtSetArg(arg[0], XtNgeometry, geom_str);
- XtSetArg(arg[1], XtNborderWidth, app_resources.borderwidth);
- /* popup = XtCreatePopupShell("popup", overrideShellWidgetClass,
- toplevel, arg, 2); */
- popup = XtCreatePopupShell("xprompt", topLevelShellWidgetClass,
- toplevel, arg, 2);
-
- box =
- XtCreateManagedWidget("box", boxWidgetClass, popup, NULL, ZERO);
-
- font = app_resources.pfont;
- bb_width = font->max_bounds.rbearing - font->min_bounds.lbearing;
- bb_height = font->max_bounds.ascent + font->max_bounds.descent;
- if (npromptargs > 1)
- sprintf(promptbuf, "%s[1/%d]:", promptargs->prompt, npromptargs);
- else
- sprintf(promptbuf, "%s:", promptargs->prompt);
- promptargs->seenprompt = TRUE;
- nprompts_seen = 1;
- XtSetArg(arg[0], XtNstring, promptbuf);
- XtSetArg(arg[1], XtNlength, maxpromptlen);
- XtSetArg(arg[2], XtNborderWidth, 0);
- XtSetArg(arg[3], XtNfont, app_resources.pfont);
- XtSetArg(arg[4], XtNeditType, XttextRead);
- XtSetArg(arg[5], XtNwidth, bb_width * maxpromptlen);
- XtSetArg(arg[6], XtNsensitive, False);
- prompt_w =
- XtCreateManagedWidget("text", asciiStringWidgetClass, box, arg, 7);
- /*
- * The following kludge is used because I couldn't find any obvious
- * way to turn off the cursor in the prompt window
- * I suppose one could define a null cursor and use that...
- */
- ctx = (TextWidget) prompt_w;
- ctx->text.sink->InsertCursor = null_cursor;
-
- font = app_resources.rfont;
- bb_width = font->max_bounds.rbearing - font->min_bounds.lbearing;
- bb_height = font->max_bounds.ascent + font->max_bounds.descent;
- strcpy(replybuf, promptargs->reply);
- XtSetArg(arg[0], XtNtextOptions, editable | scrollOnOverflow);
- XtSetArg(arg[1], XtNheight, bb_height + 6);
- XtSetArg(arg[2], XtNstring, replybuf);
- XtSetArg(arg[3], XtNlength, app_resources.rlen);
- XtSetArg(arg[4], XtNeditType, XttextEdit);
- XtSetArg(arg[5], XtNborderWidth, app_resources.insideborderwidth);
- XtSetArg(arg[6], XtNwidth, app_resources.rlen * bb_width);
- XtSetArg(arg[7], XtNinsertPosition, strlen(promptargs->reply));
- XtSetArg(arg[8], XtNfont, app_resources.rfont);
- reply_w =
- XtCreateManagedWidget("reply", asciiStringWidgetClass, box, arg, 9);
-
- t = XtParseTranslationTable(xprompt_TextTranslations);
- XtOverrideTranslations(reply_w, t);
- if (app_resources.texttranslations != NULL) {
- t = XtParseTranslationTable(app_resources.texttranslations);
- if (t == NULL) {
- fprintf(stderr, "xprompt: error parsing translation table.\n");
- exit(1);
- }
- XtOverrideTranslations(reply_w, t);
- }
- if (app_resources.texttranslationfile != NULL
- && get_user_text_translations(app_resources.texttranslationfile) < 0)
- exit(1);
-
- visible = 0;
- XtPopup(popup, XtGrabNonexclusive);
-
- /*
- * Handle the grab and/or warp, if necessary
- */
- if (app_resources.grab) {
- XGrabKeyboard(XtDisplay(reply_w), XtWindow(reply_w), False,
- GrabModeAsync, GrabModeAsync, CurrentTime);
- XSetInputFocus(XtDisplay(reply_w), XtWindow(reply_w),
- RevertToPointerRoot, CurrentTime);
- }
-
- if (app_resources.warp) {
- XWindowAttributes reply_w_attr;
- XEvent event;
- long em;
-
- if (XGetWindowAttributes(XtDisplay(reply_w), XtWindow(reply_w),
- &reply_w_attr) == 0)
- app_resources.warp = FALSE;
- else {
- Window root_return, child_return;
- int root_x_return, root_y_return;
- int win_x_return, win_y_return;
- unsigned int mask_return;
-
- orig_x = -1;
- orig_y = -1;
- /*
- * Find out where the cursor is so that it can be put back
- * before the program exits.
- */
- if (XQueryPointer(XtDisplay(popup), XtWindow(popup),
- &root_return, &child_return,
- &root_x_return, &root_y_return,
- &win_x_return, &win_y_return,
- &mask_return) != 0) {
- orig_win = root_return;
- orig_x = root_x_return;
- orig_y = root_y_return;
- }
- reply_x = reply_w_attr.width - reply_w_attr.width / 10;
- reply_y = reply_w_attr.height / 2;
-
- /*
- * The following weirdness waits for the windows to become visible
- * before warping the cursor.
- * This is necessary to avoid the case where a window manager
- * repositions things *after* the warp has occurred.
- * Suggestions on the Right Thing welcome.
- */
- if (!visible) {
- em = VisibilityChangeMask;
- XSelectInput(XtDisplay(popup), XtWindow(popup), em);
- while (1) {
- bzero(&event, sizeof(event));
- XNextEvent(XtDisplay(popup), &event);
- if (event.type == VisibilityNotify)
- break;
- }
- em = reply_w_attr.all_event_masks;
- XSelectInput(XtDisplay(popup), XtWindow(popup), em);
- }
- XWarpPointer(XtDisplay(reply_w), None, XtWindow(reply_w),
- 0, 0, 0, 0, reply_x, reply_y);
- }
- }
-
- XtMainLoop();
- }
-
- static int
- get_user_text_translations(file)
- char *file;
- {
- char *p;
- FILE *fp;
- struct stat statb;
- XtTranslations t;
-
- if ((fp = fopen(file, "r")) == NULL) {
- fprintf(stderr, "xprompt: Can't open translation file '%s'.\n", file);
- return(-1);
- }
- if (fstat(fileno(fp), &statb) < 0) {
- fprintf(stderr, "xprompt: Can't stat translation file '%s'.\n", file);
- fclose(fp);
- return(-1);
- }
- if (statb.st_size == 0) {
- fclose(fp);
- return(0);
- }
- if ((p = (char *) malloc((unsigned) statb.st_size)) == NULL) {
- fprintf(stderr, "xprompt: Can't malloc translation table.\n");
- fclose(fp);
- return(-1);
- }
- if (fread(p, statb.st_size, 1, fp) == 0) {
- fprintf(stderr, "xprompt: error reading translation table.\n");
- free(p);
- fclose(fp);
- return(-1);
- }
- fclose(fp);
- if ((t = XtParseTranslationTable(p)) == NULL) {
- fprintf(stderr, "xprompt: error parsing translation table.\n");
- free(p);
- return(-1);
- }
- XtOverrideTranslations(reply_w, t);
- free(p);
- return(0);
- }
-
- static void
- unwarp()
- {
-
- if (app_resources.warp && orig_x != -1 && orig_y != -1) {
- XWarpPointer(XtDisplay(reply_w), None, orig_win,
- 0, 0, 0, 0, orig_x, orig_y);
- XFlush(XtDisplay(reply_w));
- }
- }
-
- static void
- unparsegeometry(buf, mask, w, h, x, y)
- char *buf;
- int mask, w, h, x, y;
- {
-
- sprintf(buf, "%dx%d%c%d%c%d",
- w, h,
- mask & XNegative ? '-' : '+', x,
- mask & YNegative ? '-' : '+', y);
- }
-