home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume3 / WidgetWrap / part01 / prompt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-21  |  9.6 KB  |  348 lines

  1. /*
  2.  * prompt box -- display a prompt box on the screen.  Ask a question or
  3.  * display information, etc... accepts yes/no/cancel and/or Ok as replies.
  4.  * When the application calls the prompt box, the program "freezes" the
  5.  * screen till the user selects one of the options available and then returns
  6.  * to the application at the point in which the function was called.
  7.  *
  8.  * Because the user must reply to the question or provide some response, it
  9.  * is important not to obscure the dialog box at all -- if it is obscured,
  10.  * then it must raise itself back to the top of the window tree.  To do this,
  11.  * we must get visibility notify events.  however, there is currently no
  12.  * provision for this in the toolkit intrinsics without breaking the rule
  13.  * of opaque data structures in object oriented programming.  Thus, we must
  14.  * include the private header files.  Yet, even when visibility notify is
  15.  * set to true, and we try to get the visibility notify event, we don't get
  16.  * it!  This is probably a bug with the current intrinsics, but the code
  17.  * remains for when/if it gets fixed.  A workaround exists by checking the
  18.  * event types of all events (which is implemented here).
  19.  *
  20.  * The public routine here is PromptBox(BUTTONS, varargs)
  21.  * The idea is to call it as:
  22.  *    PromptBox(OK_BUTTON|CANCEL_BUTTON, "rm: remove %s?", file);
  23.  * The return value in this case will be OK_BUTTON *or* CANCEL_BUTTON
  24.  * depending on which the user selected.  You also have the choice of
  25.  * YES_BUTTON and NO_BUTTON --to use more than one button, OR values together.
  26.  *
  27.  * To run this file as a standalone program, compile with -DPROGRAM.
  28.  * Otherwise, this file is a module in which you can link with your
  29.  * application to have a quick dialog box (cc -c prompt.c).  If used as
  30.  * a library module, the only external global it requires is top_level --
  31.  * which is a pointer to the top_level widget returned by XtInitialize().
  32.  *
  33.  * This file is heavily dependent on the widgetwrap code accompanying this
  34.  * source file.  Note, if you are not on a sun workstation and not on a sys-v
  35.  * unix box, and you *do* have vsprintf(), define -DVPRINTF when compiling.
  36.  */
  37.  
  38. #include <stdio.h>
  39. #include <X11/Intrinsic.h>
  40. #include <X11/StringDefs.h>
  41. #include <X11/Label.h>
  42. #include <X11/Command.h>
  43. #include <X11/Box.h>
  44. #include <X11/Form.h>
  45. #include <X11/Shell.h>
  46. #include "WidgetWrap.h"
  47. #include <varargs.h>
  48. #include <sys/stat.h>
  49.  
  50. /* The following defines should exist in some header file somewhere */
  51. #define YES_BUTTON    1
  52. #define NO_BUTTON    2
  53. #define OK_BUTTON    4
  54. #define CANCEL_BUTTON    8
  55.  
  56. #define SPACING(w,n)    (((w)-((n)*(WIDTH+1)))/(n+1))
  57. #define WIDTH        60
  58.  
  59. #ifndef max
  60. #define max(a,b)    (((a) > (b))? (a) : (b))
  61. #endif /* max */
  62.  
  63. extern Widget    top_level;
  64. static Widget    prompt_shell;
  65.  
  66. static int ret_value, which_buttons;
  67. static int _do_prompt();
  68. static Widget _build_prompt(); /* returns the transient shell created */
  69.  
  70. PromptBox(va_alist)
  71. va_dcl
  72. {
  73.     char    string[BUFSIZ], *fmt;
  74.     va_list    arg_ptr;
  75.  
  76.     va_start (arg_ptr);
  77.  
  78.     which_buttons = va_arg(arg_ptr, int);
  79.  
  80.     fmt = va_arg (arg_ptr, char *);    /* get first arg */
  81.  
  82. #if defined(sun) || defined(SYSV) || defined(VPRINTF)
  83.     vsprintf(string, fmt, arg_ptr);
  84. #else /* VPRINTF */
  85.     {
  86.     /* we're on a BSD machine that has no vsprintf() */
  87.     FILE foo;
  88.     foo._cnt = BUFSIZ;
  89.     foo._base = foo._ptr = string; /* may have to cast(unsigned char *) */
  90.     foo._flag = _IOWRT+_IOSTRG;
  91.     (void) _doprnt(fmt, arg_ptr, &foo);
  92.     *foo._ptr = '\0'; /* plant terminating null character */
  93.     }
  94. #endif /* VPRINTF */
  95.     va_end (arg_ptr);
  96.     return _do_prompt(string);
  97. }
  98.  
  99. static int
  100. _do_prompt(string)
  101. String string;
  102. {
  103.     int        width;
  104.     Widget    shell;
  105.     XEvent    event;
  106.  
  107.     if (!top_level || !XtIsRealized(top_level)) {
  108.     fputs(string, stderr);
  109.     return -1; /* we haven't realized the toplevel yet! */
  110.     }
  111.  
  112.     width = max(strlen(string) * 18, 30);
  113.     shell = _build_prompt(string, width);
  114.  
  115. #ifdef X11R2
  116.     XtMoveWidget(shell,
  117.     (WidthOfScreen(XtScreen(shell)) - width)/2,
  118.     (HeightOfScreen(XtScreen(shell)) - width)/2);
  119. #else /* X11R2 */
  120.     WidgetSet(shell,
  121.     XtNx,    (WidthOfScreen(XtScreen(shell)) - width)/2,
  122.     XtNy,    (HeightOfScreen(XtScreen(shell)) - width)/2,
  123.     NULL);
  124. #endif /* X11R2 */
  125.  
  126.     /* grab exclusive to disallow other windows in this application
  127.      * from being tampered with.
  128.      */
  129.     XtPopup(shell, XtGrabExclusive);
  130.  
  131.     /*
  132.      * Loop here grabbing all events until the dialog box goes away.
  133.      * Because we've set GrabExclusive, no other windows will get
  134.      * events other than expose events, etc.., so we're safe.  After
  135.      * the popdown occurs, continue grabbing events till XtPending()
  136.      * says there are no more events to get because the widgets will
  137.      * generate Unmap events and so on.
  138.      */
  139.     for (ret_value = -1; ret_value == -1 || XtPending(); ) {
  140.     XtNextEvent(&event);
  141.     XtDispatchEvent(&event);
  142.     if (ret_value == -1 &&
  143.         event.xany.type == VisibilityNotify &&
  144.         event.xvisibility.state != VisibilityUnobscured &&
  145.         event.xvisibility.window == XtWindow(shell))
  146.         XMapRaised(XtDisplay(shell), XtWindow(shell));
  147.     }
  148.     return ret_value;
  149. }
  150.  
  151. static void
  152. raise_prompt(w, event)
  153. Widget w;
  154. XVisibilityEvent *event;
  155. {
  156.     if (event->state != VisibilityUnobscured && ret_value == -1) {
  157.     XMapRaised(XtDisplay(w), XtWindow(w));
  158.     XFlush(XtDisplay(w));
  159.     }
  160. }
  161.  
  162. static void
  163. PopDown(w, value)
  164. Widget w;
  165. int value;
  166. {
  167.     ret_value = value;
  168.     XtPopdown(prompt_shell);
  169.     XtDestroyWidget(prompt_shell);
  170. }
  171.  
  172. static Widget
  173. _build_prompt(string, width)
  174. char *string;
  175. int width;
  176. {
  177.     Widget    top, box, yes, no, cancel, ok;
  178.     int        nbuttons = 0;
  179.  
  180.     prompt_shell = WidgetCreate(NULL, transientShellWidgetClass, top_level,
  181.     XtNpopupShell,        True,
  182.     NULL);
  183.  
  184.     /* this currently doesn't work, but it should */
  185.     {
  186.     XtActionsRec foo;
  187.  
  188.     foo.string = "raise-prompt";
  189.     foo.proc = raise_prompt;
  190.     XtAddActions(&foo, 1);
  191.  
  192.     /* prompt_shell->core.visible_interest = TRUE; */
  193.     XtOverrideTranslations(prompt_shell,
  194.         XtParseTranslationTable("<Visible>: raise-prompt()"));
  195.     }
  196.  
  197.     top = WidgetCreate(NULL, boxWidgetClass, prompt_shell,
  198.     XtNhSpace,        0,
  199.     XtNvSpace,        0,
  200.     NULL);
  201.  
  202.     WidgetCreate(NULL, labelWidgetClass, top,
  203.     XtNlabel,        string,
  204.     XtNwidth,        width,
  205.     NULL);
  206.  
  207.     if (which_buttons & YES_BUTTON)
  208.     nbuttons++;
  209.     if (which_buttons & NO_BUTTON)
  210.     nbuttons++;
  211.     if (which_buttons & OK_BUTTON)
  212.     nbuttons++;
  213.     if (which_buttons & CANCEL_BUTTON)
  214.     nbuttons++;
  215.  
  216.     box = WidgetCreate(NULL, boxWidgetClass, top,
  217.     XtNfromVert,        box,
  218.     XtNwidth,        width,
  219.     XtNhSpace,        SPACING(width-3, nbuttons),
  220.     /* I'd like to use a gray pixmap here, but the athena box widget
  221.      * will free the pixmap once this is destroyed and other widgets
  222.      * that have a handle to it will die with an invalid pixmap error
  223.      * if they try to use their pixmap again.
  224.      */
  225.     /* XtNbackgroundPixmap,    XtGrayPixmap(XtScreen(top_level)), */
  226.     NULL);
  227.  
  228.     if (which_buttons & YES_BUTTON) {
  229.     yes = WidgetCreate(NULL, commandWidgetClass, box,
  230.         XtNwidth,        WIDTH,
  231.         XtNlabel,        "Yes",
  232.         NULL);
  233.     XtAddCallback(yes, XtNcallback, PopDown, YES_BUTTON);
  234.     }
  235.  
  236.     if (which_buttons & NO_BUTTON) {
  237.     no = WidgetCreate(NULL, commandWidgetClass, box,
  238.         XtNwidth,        WIDTH,
  239.         XtNlabel,        "No",
  240.         NULL);
  241.     XtAddCallback(no, XtNcallback, PopDown, NO_BUTTON);
  242.     }
  243.  
  244.     if (which_buttons & OK_BUTTON) {
  245.     ok = WidgetCreate(NULL, commandWidgetClass, box,
  246.         XtNwidth,        WIDTH,
  247.         XtNlabel,        "Ok",
  248.         NULL);
  249.     XtAddCallback(ok, XtNcallback, PopDown, OK_BUTTON);
  250.     }
  251.  
  252.     if (which_buttons & CANCEL_BUTTON) {
  253.     cancel = WidgetCreate(NULL, commandWidgetClass, box,
  254.         XtNwidth,        WIDTH,
  255.         XtNlabel,        "Cancel",
  256.         NULL);
  257.     XtAddCallback(cancel, XtNcallback, PopDown, CANCEL_BUTTON);
  258.     }
  259.  
  260.     return prompt_shell;
  261. }
  262.  
  263. #ifdef PROGRAM
  264.  
  265. Widget top_level;
  266. char *filename;
  267.  
  268. /*ARGSUSED*/
  269. static void
  270. callback_func(w, _flags)
  271. Widget w;
  272. caddr_t _flags;
  273. {
  274.     char *label;
  275.     FILE *fp;
  276.     struct stat buf;
  277.     int flags = (int)_flags;
  278.  
  279.     WidgetGet(w, XtNlabel, &label, NULL);
  280.  
  281.     if (!strcmp(label, "Create")) {
  282.     if (stat(filename, &buf) == 0)
  283.         PromptBox(OK_BUTTON, "%s already exists!", filename);
  284.     else if (PromptBox(flags, "Create file %s?", filename)
  285.         == YES_BUTTON)
  286.         if ((fp = fopen(filename, "w")) == (FILE *)NULL)
  287.         PromptBox(OK_BUTTON, "I can't create %s.", filename);
  288.         else
  289.         fclose(fp);
  290.     } else if (!strcmp(label, "Delete")) {
  291.     if (stat(filename, &buf) == -1)
  292.         PromptBox(OK_BUTTON, "%s doesn't exist!", filename);
  293.     else if (PromptBox(flags, "Delete file %s?", filename)
  294.         == YES_BUTTON)
  295.         if (unlink(filename) == -1)
  296.         PromptBox(OK_BUTTON, "I can't remove %s.", filename);
  297.     } else if (PromptBox(flags, "Really Exit?") == OK_BUTTON)
  298.     exit(0);
  299. }
  300.  
  301. main(argc, argv)
  302. unsigned int argc;
  303. char **argv;
  304. {
  305.     char trans[128], *name;
  306.     Widget box, w1, w2, w3;
  307.  
  308.     /* initialize the toolkit and register the actions */
  309.     top_level = XtInitialize(*argv, *argv, NULL, 0, &argc, argv);
  310.  
  311.     if (argc > 1)
  312.     filename = argv[1];
  313.     else
  314.     fprintf(stderr, "usage: %s filename\n", argv[0]), exit(1);
  315.  
  316.     /* create the top button and its form parent */
  317.     box = WidgetCreate(NULL, boxWidgetClass, top_level, NULL);
  318.  
  319.     w1 = WidgetCreate("button1", commandWidgetClass, box,
  320.     XtNlabel,        "Create",
  321.     XtNwidth,        200,
  322.     XtNheight,        30,
  323.     NULL);
  324.     XtAddCallback(w1, XtNcallback, callback_func,
  325.     (caddr_t)(YES_BUTTON|NO_BUTTON));
  326.  
  327.     w2 = WidgetCreate("button2", commandWidgetClass, box,
  328.     XtNlabel,        "Delete",
  329.     XtNwidth,        200,
  330.     XtNheight,        30,
  331.     NULL);
  332.     XtAddCallback(w2, XtNcallback, callback_func,
  333.     (caddr_t)(YES_BUTTON|NO_BUTTON));
  334.  
  335.     w3 = WidgetCreate("button3", commandWidgetClass, box,
  336.     XtNlabel,        "Exit",
  337.     XtNwidth,        200,
  338.     XtNheight,        30,
  339.     NULL);
  340.     XtAddCallback(w3, XtNcallback, callback_func,
  341.     (caddr_t)(OK_BUTTON|CANCEL_BUTTON));
  342.  
  343.     XtRealizeWidget(top_level);
  344.     XtMainLoop();
  345. }
  346.  
  347. #endif /* PROGRAM */
  348.