home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xmh / popup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-23  |  15.8 KB  |  504 lines

  1. /* $XConsortium: popup.c,v 2.36 91/07/23 17:43:02 converse Exp $
  2.  *
  3.  *
  4.  *              COPYRIGHT 1989
  5.  *           DIGITAL EQUIPMENT CORPORATION
  6.  *               MAYNARD, MASSACHUSETTS
  7.  *            ALL RIGHTS RESERVED.
  8.  *
  9.  * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
  10.  * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
  11.  * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
  12.  * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
  13.  *
  14.  * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
  15.  * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
  16.  * ADDITION TO THAT SET FORTH ABOVE.
  17.  *
  18.  * Permission to use, copy, modify, and distribute this software and its
  19.  * documentation for any purpose and without fee is hereby granted, provided
  20.  * that the above copyright notice appear in all copies and that both that
  21.  * copyright notice and this permission notice appear in supporting
  22.  * documentation, and that the name of Digital Equipment Corporation not be
  23.  * used in advertising or publicity pertaining to distribution of the software
  24.  * without specific, written prior permission.
  25.  */
  26.  
  27. /* popup.c -- Handle pop-up widgets. */
  28.  
  29. #include "xmh.h"
  30. #include <X11/Xaw/Cardinals.h>
  31.  
  32. typedef struct _PopupStatus {
  33.     Widget popup;        /* order of fields same as CommandStatusRec */
  34.     struct _LastInput lastInput;
  35.     char*  shell_command;    /* NULL, or contains sh -c command */
  36. } PopupStatusRec, *PopupStatus;
  37.  
  38. /* these are just strings which are used more than one place in the code */
  39. static String XmhNconfirm = "confirm";
  40. static String XmhNdialog = "dialog";
  41. static String XmhNerror = "error";
  42. static String XmhNnotice = "notice";
  43. static String XmhNokay = "okay";
  44. static String XmhNprompt = "prompt";
  45. static String XmhNvalue = "value";
  46.     
  47. /* The popups were originally parented from toplevel and neglected the
  48.  * transientFor resource.  In order not to break existing user resource
  49.  * settings for the popups, transientFor is set independent of the parent,
  50.  * which remains the toplevel widget.
  51.  */
  52.  
  53. static void DeterminePopupPosition(x_ptr, y_ptr, transFor_return)
  54.     Position    *x_ptr, *y_ptr;
  55.     Widget    *transFor_return; /* return a suitable top level shell */
  56. {
  57.     if (lastInput.win != -1) {
  58.     if (transFor_return) {
  59.         Widget    source;
  60.         source = XtWindowToWidget(XtDisplay(toplevel), lastInput.win);
  61.         while (source && !XtIsWMShell(source))
  62.         source = XtParent(source);
  63.         *transFor_return = source;
  64.     }
  65.     /* use the site of the last KeyPress or ButtonPress */
  66.     *x_ptr = lastInput.x;
  67.     *y_ptr = lastInput.y;
  68.     } else {
  69.     Widget    source;
  70.     int i = 0;
  71.     Dimension width, height;
  72.     Arg args[2];
  73.  
  74.     /* %%% need to keep track of last screen */
  75.     /* guess which screen and use the the center of it */
  76.     while (i < numScrns && !scrnList[i]->mapped)
  77.         i++;
  78.     source = ((i < numScrns) ? scrnList[i]->parent : toplevel);
  79.     XtSetArg(args[0], XtNwidth, &width);
  80.     XtSetArg(args[1], XtNheight, &height);
  81.     XtGetValues(source, args, TWO);
  82.     XtTranslateCoords(source, (Position) (width / 2),
  83.               (Position) (height / 2), x_ptr, y_ptr);
  84.     if (transFor_return) *transFor_return = source;
  85.     }
  86. }
  87.  
  88. static Boolean PositionThePopup(popup, x, y)
  89.     Widget    popup;
  90.     Position    x, y;
  91. {
  92.     /* Hack.  Fix up the position of the popup.  The xmh app defaults file
  93.      * contains an Xmh*Geometry specification; the effects of that on 
  94.      * popups, and the lack of any user-supplied geometry specification for
  95.      * popups, are mitigated here, by giving the popup shell a position.
  96.      * (Xmh*Geometry is needed in case there is no user-supplied default.)
  97.      * Returns True if an explicit geometry was inferred; false if the
  98.      * widget was repositioned to (x,y).
  99.      */
  100.  
  101.     Arg        args[4];
  102.     String     top_geom, pop_geom;
  103.  
  104.     XtSetArg( args[0], XtNgeometry, &top_geom );
  105.     XtGetValues( toplevel, args, ONE );
  106.     XtSetArg( args[0], XtNgeometry, &pop_geom );
  107.     XtGetValues( popup, args, ONE );
  108.  
  109.     if (pop_geom == NULL || pop_geom == top_geom) {
  110.     /* if same db entry, then ... */
  111.     XtSetArg( args[0], XtNgeometry, (String) NULL);
  112.     XtSetArg( args[1], XtNx, x);
  113.     XtSetArg( args[2], XtNy, y);
  114.     XtSetArg( args[3], XtNwinGravity, SouthWestGravity);
  115.     XtSetValues( popup, args, FOUR);
  116.     return False;
  117.     }
  118.     return True;
  119. }
  120.  
  121.  
  122. static void CenterPopupPosition(widget, popup, px, py)
  123.     Widget    widget;
  124.     Widget    popup;
  125.     Position    px, py;
  126. {
  127.     Position    x, y;
  128.     Position    nx, ny;
  129.     Arg        args[3];
  130.  
  131.     if (widget == NULL) return;
  132.     XtSetArg(args[0], XtNx, &x);
  133.     XtSetArg(args[1], XtNy, &y);
  134.     XtGetValues(popup, args, TWO);
  135.     if (x == px && y == py) {
  136.  
  137.     /* Program sets geometry.  Correct our earlier calculations. */
  138.  
  139.     nx = (GetWidth(widget) - GetWidth(popup)) / 2;
  140.     ny = (GetHeight(widget) - GetHeight(popup)) / 2;
  141.     if (nx < 0) nx = 0;
  142.     if (ny < 0) ny = 0;
  143.     XtTranslateCoords(widget, nx, ny, &x, &y);
  144.     XtSetArg(args[0], XtNx, x);
  145.     XtSetArg(args[1], XtNy, y);
  146.     XtSetArg(args[2], XtNwinGravity, CenterGravity);
  147.     XtSetValues(popup, args, THREE);
  148.     }
  149. }
  150.      
  151.  
  152. /* Insure that the popup is wholly showing on the screen.
  153.    Optionally center the widget horizontally and/or vertically
  154.    on current position.
  155.  */
  156.  
  157. static void InsureVisibility(popup, popup_child, x, y, centerX, centerY)
  158.     Widget    popup, popup_child;
  159.     Position    x, y;        /* assert: current position = (x,y) */
  160.     Boolean    centerX, centerY;
  161. {
  162.     Position    root_x, root_y;
  163.     Dimension    width, height, border;
  164.     Arg        args[3];
  165.  
  166.  
  167.     XtSetArg( args[0], XtNwidth, &width );
  168.     XtSetArg( args[1], XtNheight, &height );
  169.     XtSetArg( args[2], XtNborderWidth, &border );
  170.     XtGetValues( popup, args, THREE );
  171.  
  172.     XtTranslateCoords(popup_child, (Position)0, (Position)0, &root_x, &root_y);
  173.     if (centerX) root_x -= width/2 + border;
  174.     if (centerY) root_y -= height/2 + border;
  175.     if (root_x < 0) root_x = 0;
  176.     if (root_y < 0) root_y = 0;
  177.     border <<= 1;
  178.  
  179.     if ((int)(root_x + width + border) > WidthOfScreen(XtScreen(toplevel))) {
  180.     root_x = WidthOfScreen(XtScreen(toplevel)) - width - border;
  181.     }
  182.     if ((int)(root_y + height + border) > HeightOfScreen(XtScreen(toplevel))) {
  183.     root_y = HeightOfScreen(XtScreen(toplevel)) - height - border;
  184.     }
  185.  
  186.     if (root_x != x || root_y != y) {
  187.     XtSetArg( args[0], XtNx, root_x );
  188.     XtSetArg( args[1], XtNy, root_y );
  189.     XtSetValues( popup, args, TWO );
  190.     }
  191. }
  192.  
  193.  
  194. /*ARGSUSED*/
  195. void DestroyPopup(widget, client_data, call_data)
  196.     Widget        widget;        /* unused */
  197.     XtPointer        client_data;
  198.     XtPointer        call_data;    /* unused */
  199. {
  200.     Widget        popup = (Widget) client_data;
  201.     XtPopdown(popup);
  202.     XtDestroyWidget(popup);
  203. }
  204.  
  205. void WMDeletePopup(popup, event)
  206.     Widget    popup;    /* transient shell */
  207.     XEvent*    event;
  208. {
  209.     String    shellName;
  210.     String    buttonName;
  211.     Widget    button;
  212.  
  213.     shellName = XtName(popup);
  214.     if (strcmp(shellName, XmhNconfirm) == 0)
  215.     buttonName = "*no";
  216.     else if (strcmp(shellName, XmhNprompt) == 0)
  217.     buttonName = "*cancel";
  218.     else if (strcmp(shellName, XmhNnotice) == 0)
  219.     buttonName = "*confirm";
  220.     else if (strcmp(shellName, XmhNerror) == 0)
  221.     buttonName = "*OK";
  222.     else
  223.     return;        /* WM may kill us */
  224.  
  225.     button = XtNameToWidget(popup, buttonName);
  226.     if (! button) return;
  227.     XtCallActionProc(button, "set", event, (String*)NULL, ZERO);
  228.     XtCallActionProc(button, "notify", event, (String*)NULL, ZERO);
  229.     XtCallActionProc(button, "unset", event, (String*)NULL, ZERO);
  230. }
  231.  
  232. static void TheUsual(popup)
  233.     Widget    popup;    /* shell */
  234. {
  235.     XtInstallAllAccelerators(popup, popup);
  236.     XtAugmentTranslations(popup, app_resources.wm_protocols_translations);
  237.     XtRealizeWidget(popup);
  238.     XDefineCursor(XtDisplay(popup), XtWindow(popup), app_resources.cursor);
  239.     (void) XSetWMProtocols(XtDisplay(popup), XtWindow(popup), 
  240.                protocolList, XtNumber(protocolList));
  241. }
  242.  
  243.  
  244. /*ARGSUSED*/
  245. void XmhPromptOkayAction(w, event, params, num_params)
  246.     Widget    w;        /* the "value" widget in the Dialog box */
  247.     XEvent    *event;        /* unused */
  248.     String    *params;    /* unused */
  249.     Cardinal    *num_params;    /* unused */
  250. {
  251.     XtCallCallbacks(XtNameToWidget(XtParent(w), XmhNokay), XtNcallback,
  252.             (XtPointer)XtParent(w));
  253. }
  254.  
  255.  
  256. void PopupPrompt(transientFor, question, okayCallback)
  257.     Widget        transientFor;    /* required to be a top-level shell */
  258.     String        question;        /* the prompting string */
  259.     XtCallbackProc    okayCallback;        /* CreateFolder() */
  260. {
  261.     Widget        popup;
  262.     Widget        dialog;
  263.     Widget        value;
  264.     Position        x, y;
  265.     Boolean        positioned;
  266.     Arg            args[3];
  267.     static XtTranslations PromptTextTranslations = NULL;
  268.  
  269.     DeterminePopupPosition(&x, &y, (Widget*)NULL);
  270.     XtSetArg(args[0], XtNallowShellResize, True);
  271.     XtSetArg(args[1], XtNinput, True);
  272.     XtSetArg(args[2], XtNtransientFor, transientFor);
  273.     popup = XtCreatePopupShell(XmhNprompt, transientShellWidgetClass, toplevel,
  274.                    args, THREE);
  275.     positioned = PositionThePopup(popup, x, y);
  276.  
  277.     XtSetArg(args[0], XtNlabel, question);
  278.     XtSetArg(args[1], XtNvalue, "");
  279.     dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
  280.                    TWO);
  281.     XtSetArg(args[0], XtNresizable, True);
  282.     XtSetValues( XtNameToWidget(dialog, "label"), args, ONE);
  283.     value = XtNameToWidget(dialog, XmhNvalue);
  284.     XtSetValues( value, args, ONE);
  285.     if (! PromptTextTranslations)
  286.     PromptTextTranslations = XtParseTranslationTable
  287.         ("<Key>Return: XmhPromptOkayAction()\n\
  288.               Ctrl<Key>R:  no-op(RingBell)\n\
  289.               Ctrl<Key>S:  no-op(RingBell)\n");
  290.     XtOverrideTranslations(value, PromptTextTranslations);
  291.  
  292.     XawDialogAddButton(dialog, XmhNokay, okayCallback, (XtPointer) dialog);
  293.     XawDialogAddButton(dialog, "cancel", DestroyPopup, (XtPointer) popup);
  294.     TheUsual(popup);
  295.     InsureVisibility(popup, dialog, x, y, !positioned, False);
  296.     XtPopup(popup, XtGrabNone);
  297. }
  298.  
  299.  
  300. /* ARGSUSED */
  301. static void FreePopupStatus( w, closure, call_data )
  302.     Widget w;            /* unused */
  303.     XtPointer closure;
  304.     XtPointer call_data;    /* unused */
  305. {
  306.     PopupStatus popup = (PopupStatus)closure;
  307.     XtPopdown(popup->popup);
  308.     XtDestroyWidget(popup->popup);
  309.     if (popup->shell_command)
  310.     XtFree(popup->shell_command);
  311.     XtFree((char *) closure);
  312. }
  313.  
  314.  
  315. void PopupNotice(message, callback, closure)
  316.     String        message;
  317.     XtCallbackProc    callback;
  318.     XtPointer        closure;
  319. {
  320.     PopupStatus popup_status = (PopupStatus)closure;
  321.     Widget transientFor;
  322.     Widget dialog;
  323.     Widget value;
  324.     Position x, y;
  325.     Arg args[3];
  326.     char command[65], label[128];
  327.  
  328.     if (popup_status == (PopupStatus)NULL) {
  329.     popup_status = XtNew(PopupStatusRec);
  330.     popup_status->lastInput = lastInput;
  331.     popup_status->shell_command = (char*)NULL;
  332.     }
  333.     if (! popup_status->shell_command) {
  334.     /* MH command */
  335.     if (sscanf( message, "%64s", command ) != 1)
  336.         (void) strcpy( command, "system" );
  337.     else {
  338.         int l = strlen(command);
  339.         if (l && command[--l] == ':')
  340.         command[l] = '\0';
  341.     }
  342.     (void) sprintf( label, "%.64s command returned:", command );
  343.     } else {
  344.     /* arbitrary shell command */
  345.     int len = strlen(popup_status->shell_command);
  346.     (void) sprintf(label, "%.88s %s\nshell command returned:",
  347.                popup_status->shell_command,
  348.                ((len > 88) ? "[truncated]" : ""));
  349.     }
  350.  
  351.     DeterminePopupPosition(&x, &y, &transientFor);
  352.     XtSetArg( args[0], XtNallowShellResize, True );
  353.     XtSetArg( args[1], XtNinput, True );
  354.     XtSetArg( args[2], XtNtransientFor, transientFor);
  355.     popup_status->popup = XtCreatePopupShell(XmhNnotice,
  356.                  transientShellWidgetClass, toplevel, args, THREE);
  357.     PositionThePopup(popup_status->popup, x, y);
  358.  
  359.     XtSetArg( args[0], XtNlabel, label );
  360.     XtSetArg( args[1], XtNvalue, message );
  361.     dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass,
  362.                    popup_status->popup, args, TWO);
  363.  
  364.     /* The text area of the dialog box will not be editable. */
  365.     value = XtNameToWidget(dialog, XmhNvalue);
  366.     XtSetArg( args[0], XtNeditType, XawtextRead);
  367.     XtSetArg( args[1], XtNdisplayCaret, False);
  368.     XtSetValues( value, args, TWO);
  369.     XtOverrideTranslations(value, NoTextSearchAndReplace);
  370.  
  371.     XawDialogAddButton( dialog, XmhNconfirm,
  372.                ((callback != (XtCallbackProc) NULL)
  373.                   ? callback : (XtCallbackProc) FreePopupStatus), 
  374.                (XtPointer) popup_status
  375.               );
  376.  
  377.     TheUsual(popup_status->popup);
  378.     InsureVisibility(popup_status->popup, dialog, x, y, False, False);
  379.     XtPopup(popup_status->popup, XtGrabNone);
  380. }
  381.  
  382.  
  383. void PopupConfirm(center_widget, question, affirm_callbacks, negate_callbacks)
  384.     Widget        center_widget;    /* where to center; may be NULL */
  385.     String        question;
  386.     XtCallbackList    affirm_callbacks;
  387.     XtCallbackList    negate_callbacks;
  388. {
  389.     Widget    popup;
  390.     Widget    dialog;
  391.     Widget    button;
  392.     Widget    transientFor;
  393.     Position    x, y;
  394.     Arg        args[3];
  395.     static XtCallbackRec callbacks[] = {
  396.     {DestroyPopup,        (XtPointer) NULL},
  397.     {(XtCallbackProc) NULL,    (XtPointer) NULL}
  398.     };
  399.  
  400.     DeterminePopupPosition(&x, &y, &transientFor);
  401.     XtSetArg(args[0], XtNinput, True);
  402.     XtSetArg(args[1], XtNallowShellResize, True);
  403.     XtSetArg(args[2], XtNtransientFor, transientFor);
  404.     popup = XtCreatePopupShell(XmhNconfirm, transientShellWidgetClass,
  405.                    toplevel, args, THREE);
  406.     PositionThePopup(popup, x, y); 
  407.  
  408.     XtSetArg(args[0], XtNlabel, question);
  409.     dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, popup, args,
  410.                    ONE);
  411.     
  412.     callbacks[0].closure = (XtPointer) popup;
  413.     XtSetArg(args[0], XtNcallback, callbacks);
  414.     button = XtCreateManagedWidget("yes", commandWidgetClass, dialog, 
  415.                    args, ONE);
  416.     if (affirm_callbacks)
  417.     XtAddCallbacks(button, XtNcallback, affirm_callbacks);
  418.  
  419.     button = XtCreateManagedWidget("no", commandWidgetClass, dialog, 
  420.                    args, ZERO);
  421.     XtAddCallback(button, XtNcallback, DestroyPopup, (XtPointer) popup);
  422.     if (negate_callbacks)
  423.     XtAddCallbacks(button, XtNcallback, negate_callbacks);
  424.  
  425.     TheUsual(popup);
  426.     CenterPopupPosition(center_widget, popup, x, y);
  427.     InsureVisibility(popup, dialog, x, y, False, False);
  428.     XtPopup(popup, XtGrabNone);
  429. }
  430.  
  431.  
  432. void PopupError(widget, message)
  433.     Widget    widget;    /* transient for this top-level shell, or NULL */
  434.     String    message;
  435. {
  436.     Widget    transFor, error_popup, dialog;
  437.     Position    x, y;
  438.     Boolean    positioned;
  439.     Arg        args[3];
  440.     static XtCallbackRec callbacks[] = {
  441.     {DestroyPopup,        (XtPointer) NULL},
  442.     {(XtCallbackProc) NULL,    (XtPointer) NULL}
  443.     };
  444.  
  445.     transFor = widget;
  446.     DeterminePopupPosition(&x, &y, transFor ? (Widget*)NULL : &transFor);
  447.  
  448.     XtSetArg(args[0], XtNallowShellResize, True);
  449.     XtSetArg(args[1], XtNinput, True);
  450.     XtSetArg(args[2], XtNtransientFor, transFor);
  451.     error_popup = XtCreatePopupShell(XmhNerror, transientShellWidgetClass,
  452.                      toplevel, args, THREE);
  453.     positioned = PositionThePopup(error_popup, x, y);
  454.  
  455.     XtSetArg(args[0], XtNlabel, message);
  456.     dialog = XtCreateManagedWidget(XmhNdialog, dialogWidgetClass, error_popup,
  457.                    args, ONE);
  458.     callbacks[0].closure = (XtPointer) error_popup;
  459.     XtSetArg(args[0], XtNcallback, callbacks);
  460.     XawDialogAddButton(dialog, "OK", DestroyPopup, (XtPointer) error_popup);
  461.     TheUsual(error_popup);
  462.     InsureVisibility(error_popup, dialog, x, y, !positioned, !positioned);
  463.     XtPopup(error_popup, XtGrabNone);
  464. }
  465.  
  466. /*ARGSUSED*/
  467. void PopupWarningHandler(name, type, class, msg, params, num)
  468.     String name;
  469.     String type;
  470.     String class;
  471.     String msg;
  472.     String *params;
  473.     Cardinal *num;
  474. {
  475.     char *ptr;
  476.     int i;
  477.     String par[10];
  478.     char message[500];
  479.     char buffer[500];
  480.     static Boolean allowPopup = True; /* protect against recursion */
  481.  
  482.     XtGetErrorDatabaseText(name, type, class, msg, buffer, 500);
  483.  
  484.     if (params && num && *num) {
  485.     i = (*num <= 10) ? *num : 10;
  486.     bcopy((char*)params, (char*)par, i * sizeof(String));
  487.     bzero( &par[i], (10-i) * sizeof(String));
  488.     if (*num > 10)
  489.         par[9] = "(truncated)";
  490.     (void) sprintf(message, buffer, par[0], par[1], par[2], par[3],
  491.                par[4], par[5], par[6], par[7], par[8], par[9]);
  492.     ptr = message;
  493.     } else {
  494.     ptr = buffer;
  495.     }
  496.     if (allowPopup) {
  497.     allowPopup = False;
  498.     PopupError((Widget)NULL, ptr); 
  499.     allowPopup = True;
  500.     } else {
  501.     fprintf(stderr, ptr);
  502.     }
  503. }
  504.