Path: utzoo!utgpu!watmath!att!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!odi!mlm
From: mlm@odi.com (Mitchell Model)
Newsgroups: comp.windows.x
Subject: Re: help
Message-ID: <1989Aug15.213710.3103@odi.com>
Date: 15 Aug 89 21:37:10 GMT
References: <3982@ncar.ucar.edu>
Organization: Object Design, Inc.
Lines: 306
In-reply-to: clyne@redcloud.ucar.edu's message of 14 Aug 89 23:10:24 GMT

In article <3982@ncar.ucar.edu> clyne@redcloud.ucar.edu (John Clyne) writes:

   This should not be too hard to do but I haven't been able to figure out
   a simple solution: I want to have a generic warning routine, call it
   display_warning(), that when invoked will popup and display a warning message
   (under the Xt instrinics) and require the user to select a proceed or 
   cancel button. The problem
   is that I want display_warning() to return a value depending on the 
   user's selection. How do I get display_warning() to wait until a selection
   has been made before returning?. display_warning() also needs to know
   which selection has been made and indicate this in the return. Is there
   a simple way to due this?


One way is to do the following after XtPopup(shell, XtGrabExclusive):
	flag = True;
	while (flag) ProcessOneEvent(XtDisplay(shell));
	return result;

with:

	void ProcessOneEvent(display)
	    Display *display;
	{
	    static XEvent event;

	    XNextEvent(display, &event);
	    XtDispatchEvent(&event);
	}

There's a further trick, though: your callback functions have to set
result, popdown shell, and set flag to false.  There are various ways
to do this, all awkward, including global variables and packaging up
stuff like this into a record that you provide as the client_data for
the callback.

Here's the complete code for a Yes/No confirmation widget.  I
originally took this code from contrib/hacks/xpostit/confirm.c then
hacked it up to wait for user response as well as add some other
features my application needed (in particular warping the cursor back
to where it was before the confirmation popped up).  Thanks to David Curry,
xpostit author, for xpostit: a really useful utility and a source
of well-structured, commented, and X-instructive code.


	Mitchell L Model
	Director, HeadStart Program
	Object-Design, Inc.
	One New England Park
	Burlington MA 01803
	(617) 270-9797
	mlm@odi.com

==============================================================================
/* confirm -- copied from $x/contrib/hacks/xpostit/confirm.c and xpostit.h
   then modified to be simpler -- not use callbacks, just return true or false
*/


/* mlm:

   5-17-89      added wait loop

   3-17-89	changed to just return Bool

   3-16-89	added toplevel to ConfirmIt arg list,
   		to make this completely independent

*/

#include 			/* for Bool, etc. */

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "confirm.h"
#include "xutil.h"

/* from xpostit.h */
#define SetArg(which, val)	XtSetArg(args[nargs], (which),\
					(XtArgVal) (val)); nargs++


typedef struct _result
{
    Bool *popflg, *var;
    int root_x, root_y;
    Window root;
    Widget shell;
} *Result;

static Result MakeResult(shell, popflg, resultvar, root, root_x, root_y)
    Bool *popflg, *resultvar;
    Window root;
    int root_x, root_y;
    Widget shell;
{
    Result rec = (Result) malloc(sizeof(struct _result));

    rec->popflg = popflg;
    rec->var = resultvar;
    rec->root = root;
    rec->root_x = root_x;
    rec->root_y = root_y;
    rec->shell = shell;
    
    return rec;
}



/* ARGSUSED */

/*
 * ClearConfirm - get rid of the confirmation box.
 */
/* ARGSUSED */
void
ClearConfirm(w, val, result)
    Widget w;
    Bool val;
    Result result;
{
    Display *display = XtDisplay(w);

    XtPopdown(result->shell);
    XtDestroyWidget(result->shell);
    *result->popflg = False;
    *result->var = val;

    XWarpPointer(display, None, result->root, 0, 0, 0, 0,
		 result->root_x, result->root_y);
}

/* ARGSUSED */
static void Yes(w, result, call_data)
    Widget w;
    Result result;
    caddr_t call_data;			/* unused */
{
    ClearConfirm(w, True, result);
}

/* ARGSUSED */
static void No(w, result, call_data)
    Widget w;				/* unused */
    Result result;
    caddr_t call_data;
{
    ClearConfirm(w, False, result);
}


#define btnsepr 8

static void adjust(label, yes, no)
    Widget label, yes, no;
{
    Arg args[2];
    int nargs;
    
    int labelwidth, yeswidth, btnborder, btnwidth;

    if (!label)
	labelwidth = 0;
    else
	{
	    nargs = 0;
	    SetArg(XtNwidth, NULL);
	    XtGetValues(label, args, 1);
	    labelwidth = args[0].value;
	}
    
    nargs = 0;
    SetArg(XtNwidth, NULL);
    SetArg(XtNborder, NULL);
    XtGetValues(yes, args, 2);
    yeswidth = args[0].value;
    btnborder = args[1].value;

    btnwidth = (labelwidth-btnsepr-4*btnborder)/2;
    if (btnwidth < yeswidth) btnwidth = yeswidth;

    nargs = 0;
    SetArg(XtNwidth, btnwidth);
    XtSetValues(yes, args, 1);
    XtSetValues(no, args, 1);
    
}

/*
 * Confirm - put up a window asking for confirmation.
 */
Bool Confirm(toplevel, prompt)
    Widget toplevel;
    char* prompt;
{
    static Arg args[4];
    register int nargs;
    static Bool inited = False;
    Bool poppedup=False, result=False;
    static Widget shell, form, label, yes, no;
    static int root_x, root_y, child_x, child_y, buttons;
    static Window root, child;
    static Result resultrec;

    inited = False;			/* recreate each time for now */
    

    /*
     * Find out where the mouse is, so we can put the confirmation
     * box right there.
     */
    XQueryPointer(XtDisplay(toplevel), XtWindow(toplevel),
		  &root, &child,
		  &root_x, &root_y, &child_x, &child_y, &buttons);

    /*
     * If we need to construct the confirmation box do that,
     * otherwise just reset the position and callbacks and
     * put it up again.
     */
    if (!inited)
	{

	    nargs = 0;
	    SetArg(XtNx, root_x);
	    SetArg(XtNy, root_y);
	    SetArg(XtNinput, True);
	    shell = XtCreatePopupShell("Confirm", transientShellWidgetClass,
				       toplevel, args, nargs);

	    nargs = 0;
	    form = XtCreateManagedWidget("form", formWidgetClass,
				  shell, args, nargs);

	    if (!prompt)
		label = NULL;
	    else
		{
		    nargs = 0;
		    SetArg(XtNlabel, prompt);
		    SetArg(XtNborderWidth, 0);
		    label = XtCreateManagedWidget("prompt", labelWidgetClass,
						 form, args, nargs);
		}

	    nargs = 0;
	    if (prompt)
		{
		    SetArg(XtNfromVert, label);
		    SetArg(XtNvertDistance, 12);
		}
	    yes = XtCreateManagedWidget("yes", commandWidgetClass,
				       form, args, nargs);

	    nargs = 0;
	    SetArg(XtNfromHoriz, yes);
	    SetArg(XtNhorizDistance, btnsepr);
	    if (prompt)
		{
		    SetArg(XtNfromVert, label);
		    SetArg(XtNvertDistance, 12);
		}
	    no = XtCreateManagedWidget("no", commandWidgetClass,
					   form, args, nargs);

	    adjust(label, yes, no);
	    XtRealizeWidget(shell);
	    inited = True;
	}
    else {
	/*
	 * Reset the confirmation box position.
	 */
	nargs = 0;
	SetArg(XtNx, root_x);
	SetArg(XtNy, root_y);
	XtSetValues(shell, args, nargs);
    }

    resultrec = MakeResult(shell, &poppedup, &result, root, root_x, root_y);
    XtAddCallback(yes, XtNcallback, Yes, resultrec);
    XtAddCallback(no, XtNcallback, No, resultrec);

    XtPopup(shell, XtGrabExclusive);
    poppedup = True;

    while(poppedup) ProcessOneEvent(XtDisplay(shell));

    return result;
}

#undef btnsepr
	    

-- 

	Mitchell L Model
	Director, HeadStart Program
	Object-Design, Inc.