[comp.sources.x] v03i076: WidgetWrap -- varargs interface Widget routines, Part01/01

argv@island.uu.net (Dan Heller) (04/20/89)

Submitted-by: Dan Heller <island!argv@cad.berkeley.edu>
Posting-number: Volume 3, Issue 76
Archive-name: WidgetWrap/part01

[ This is the posting of the widget wrap that I discussed in comp.windows.x --
  I have written a sample program which demonstrates how to use the calls
  effectively.  It creates various widgets: top-level, popup, command and
  label widgets.  As usual, comments and other feedback welcome. --argv ]

#!/bin/sh
# This is a shell archive file. Remove everything above this line
# to unbundle. chmod +x "thisfile", then run it: e.g. % thisfile
# SHAR archive format.  Archive created Thu Apr 20 02:11:02 PDT 1989
# file contains: 
#	README
#	WidgetWrap.man
#	Patchlevel.h
#	WidgetWrap.c
#	WidgetWrap.h
#	prompt.c
echo x - README
sed 's/^X//' > README <<'+END+OF+README'
XThe source code and documentation included here was written by:
X    Dan Heller <island!argv@cad.berkeley.edu>
X(also see notes about sample program at the end of this file)
X-----------------
X
XWidgetWrap.c -- variable argument style programmer interfaces to widgets:
X   WidgetCreate(name, class, parent, varargs...);
X   WidgetSet(name, varargs);
X   WidgetGet(name, varargs);
X   GenericWidgetName(buf);
X
XThe purpose of this module is to allow the programmer to Create
Xwidgets and set/get widget attributes via a variable argument list
Xstyle of function call.  This eliminates the need for many local
Xvariables and bothersome XtSetArg() calls and so forth.  An example
Xof usage:
X
X   Widget foo;
X
X   foo = WidgetCreate("foo", labelWidgetClass, toplevel,
X	XtNlabel,		"Widget",
X	XtNforeground,	WhitePixelOfScreen(XtScreen(toplevel)),
X	XtNbackground,	BlackPixelOfScreen(XtScreen(toplevel)),
X	XtNborderWidth,	1,
X	NULL);
X
XAs you can see, the list must be NULL terminated.  You may pass up to
Xto MAXARGS argument pairs.  Increase this number in WidgetWrap.h if
Xnecessary.
X
XBy default, WidgetCreate calls XtCreateManagedWidget() -- if you want to
Xcreate an unmanaged widget, you can use the parameter pair:
X
X   XtNmanaged		False
X
X(passing "True" is a no-op.)  Similarly, if you want to unmanage a widget
Xthat has already been created, you can pass the same parameter pair in
Xa WidgetSet call.
X
XIf you already have an array of Arg's then you can use the parameter:
X   XtNargList
Xthis attribute takes _two_ parameters: the arglist array and the number
Xof elements in the array.  Now it is possible to pass attributes to the
XWidgetCreate(), WidgetSet() and WidgetGet() that are probably common to
Xmany widgets to be created or reset.
X
XFor example, you have:
X
Xstatic Arg args[] = {
X    XtNforeground,	black,
X    XtNbackground,	white,
X    XtNwidth,		20,
X    XtNheight,		10,
X};
X... later in your code you have ...
X
X    foo = WidgetCreate("bar", widgetClass, toplevel,
X	XtNargList,	args, XtNumber(args),
X	NULL);
X
XFinally, there are two more XtN's that the widgetwrap code provides.
XYou can create toplevel application shell widgets and popup shells
Xas well as other widget types by passing these parameters:
X
X   XtNpopupShell		pass "True" to create a PopupShellWidget.
X   XtNapplicShell		pass "True" to create an applicationShellWidget
X
XThese obsolete the need for XtCreatePopupShell() and XtCreateApplicationShell()
XNote that for both of these, the "parent" parameter is ignored for the
XWidgetCreate() call (you may pass anything, but the parent parameter remains
Xthere for consistency).
X
XThe next thing that the WidgetWrap library comes with is a function to
Xgenerate widget names.  Most large applciations will create a large number
Xof widgets.  All widgets have to have unique names, and as noted by the
Xexamples above, the names are typically constant strings which takes up
Xmemory, disk spaces, etc...  Most of the time, there are a great number
Xof widgets in which their names are unused ... So, if WidgetCreate() gets
XNULL as the name of the widget, then a widget name will be created
Xautomatically.  The introduction of this function has saved about 10K
Xin text space on an application with about 300 widgets.
X
XBefore I finish, a note about varargs.  Note that there are many different
Ximplementations of varargs.  To maintain portability, it is important
Xto never return from a function that uses varargs without calling va_end().
Xva_start() and va_end() should always exist in the same block of {}'s.
XThere can be blocks between them, but va_end() shouldn't be in a block
Xinside of the va_start() stuff.  This is to allow support for weird
Ximplementations which define va_start() to something like:  ".... { "
X(pyramid computers for one).
XAlso, if you use varargs, never declare "known" arguments; extract them
Xfrom the vararg list later.
X
X-----------------------
XThere is a demo program which demonstrates how to use the widgetwrap code
Xand also provides a nifty little "prompt box".  the public routine is called
XPromptBox() and the idea is to call it as:
X
X   PromptBox(OK_BUTTON|CANCEL_BUTTON, "rm: remove %s?", file);
X
XThe return value in this case will be OK_BUTTON *or* CANCEL_BUTTON
Xdepending on which the user selected.  You also have the choice of
XYES_BUTTON and NO_BUTTON --to use more than one button, OR values together.
+END+OF+README
echo '-rw-rw-r--  1 argv         4325 Apr 20 01:56 README    (as sent)'
chmod u=rw,g=rw,o=r README
ls -l README
echo x - WidgetWrap.man
sed 's/^X//' > WidgetWrap.man <<'+END+OF+WidgetWrap.man'
X.\" This man page was written by Dan Heller <island!argv@sun.com>
X.\" or <dheller@ucbcory.berkeley.edu>
X.TH WidgetWrap 3X "" "1 March 1988" "X Version 11" 
X.SH NAME
XWidgetCreate, WidgetSet, WidgetGet \- programmer's convenience routines
X.SH SYNTAX
XWidgetCreate\^(\fIname\fP\^, \fIclass\fP\^, \fIparent\fP\^, \fIvarargs\fP)
X.br
X      char *\fIname\fP\^;
X.br
X      WidgetClass \fIclass\fP\^;
X.br
X      Widget \fIparent\fP\^;
X.LP
XWidgetSet\^(\^\fIwidget\fP, \fIvarargs\fP\^)
X.br
X      Widget *\fIwidget\fP\^;
X.LP
XWidgetGet\^(\^\fIwidget\fP, \fIvarargs\fP\^)
X.br
X      Widget *\fIwidget\fP\^;
X.LP
Xchar *
XGenericWidgetName\^(\^\fIbuf\fP)
X.br
X      char *\fIbuf\fP\^;
X.SH ARGUMENTS
X.IP \fIbuf\fP 1i
XBuffer to place new widget name.
X.IP \fIclass\fP 1i
XThe class of the widget to be created.
X.IP \fIname\fP 1i
XThe name of the widget when created.
X.IP \fIparent\fP 1i
XThe parent of the widget to be created.
X.IP \fIwidget\fP 1i
XThe widget to set or get attributes.
X.SH DESCRIPTION
X.ds WC .PN WidgetCreate
XThe purpose of these functions is to allow the programmer to create
Xwidgets and set and get widget attributes via a variable argument list
Xstyle of function call.  This eliminates the need for many local
Xvariables and bothersome XtSetArg() calls and so forth.  An example
Xof usage:
X.sp
X.in +2
X.nf
XWidget foo;
X.sp
Xfoo = WidgetCreate("foo", labelWidgetClass, toplevel,
X.in +2
XXtNlabel,           "Widget",
XXtNforeground,      WhitePixelOfScreen(XtScreen(toplevel)),
XXtNbackground,      BlackPixelOfScreen(XtScreen(toplevel)),
XXtNborderWidth,     1,
XNULL);
X.sp
X.fi
X.in -4
XAs you can see, the list must be NULL terminated.  You may pass up to
Xto MAXARGS argument pairs (which is defined in WidgetWrap.h).  There are
Xspecial args available to the Create/Get/Set functions that are available:
X.sp
X.in +2
XXtNmanaged\ \ \ \ pass "False" to create a non-managed widget.
XXtNargList\ \ \ \ takes \fItwo\fP parameters.
X.in -2
X.sp
XThe XtNargList makes it possible to pass attributes to the Create/Get/Set
Xcalls that are probably common to many widgets to be created or reset.
X.sp
X.in +2
X.nf
Xstatic Arg args[] = {
X.in +2
XXtNforeground,   black,
XXtNbackground,   white,
XXtNwidth,        20,
XXtNheight,       10,
X.ti -2
X};
X.sp
X.ti -2
Xfoo = WidgetCreate(NULL, widgetClass, toplevel,
XXtNargList,      args, XtNumber(args),
XNULL);
X.in -4
X.fi
X.sp
XThere are two other XtN's that the widgetwrap code provides.
XYou can create toplevel application shell widgets and popup shells
Xas well as other widget types by passing these parameters:
X.sp
X.ti +2
XXtNpopupShell \ \ \ \ pass "True" to create a PopupShellWidget.
X.ti +2
XXtNapplicShell \ \ \ \ pass "True" to create an applicationShellWidget
X.sp
XThese obsolete the need for XtCreatePopupShell() and XtCreateApplicationShell()
XNote that for both of these, the "parent" parameter is ignored for the
XWidgetCreate() call (you may pass anything, but the parent parameter remains
Xthere for consistency).
X.sp
XMost large applications will create huge numbers of widgets which the
Xprogrammer has to think up unique names for all of them.  What's more,
Xtypically, as noted by the examples above, the names are constant strings
Xwhich takes up memory, disk spaces, etc...  So, if WidgetCreate() gets
XNULL as the name of the widget, then a widget name will be created
Xautomatically by calling GenericWidgetName() since most of the time,
Xuser's don't care what the name of a widget is, this capability is available.
X.SH DIAGNOSTICS
XWidgetCreate() will return NULL if a widget cannot be created.  It uses
Xthe routines (and is a front end for) XtCreateWidget(),
XXtCreateManagedWidget(), XtCreatePopupShell(), and XtCreateApplicationShell().
X.SH BUGS
XThe number of parameters is limited to a constant size defined in the public
Xinclude file \*QWidgetWrap.h\*U but should be set to a reasonable size.  If
Xthe number of parameters exceeds that size, a warning will be printed.
XIf the calling function is WidgetSet() or WidgetGet(), the warning is advisory
Xonly and the runtime code is not effected.  However, if the number of arguments
Xare exceeded for WidgetCreate() calls, then the widget is not created and NULL
Xis returned.
+END+OF+WidgetWrap.man
echo '-rw-r--r--  1 argv         4130 Apr 17 13:05 WidgetWrap.man    (as sent)'
chmod u=rw,g=r,o=r WidgetWrap.man
ls -l WidgetWrap.man
echo x - Patchlevel.h
sed 's/^X//' > Patchlevel.h <<'+END+OF+Patchlevel.h'
X#define PATCHLEVEL 1
+END+OF+Patchlevel.h
echo '-rw-rw-r--  1 argv           21 Apr 17 12:56 Patchlevel.h    (as sent)'
chmod u=rw,g=rw,o=r Patchlevel.h
ls -l Patchlevel.h
echo x - WidgetWrap.c
sed 's/^X//' > WidgetWrap.c <<'+END+OF+WidgetWrap.c'
X/*
X * WidgetWrap.c -- variable argument style programmer interfaces to widgets:
X *    WidgetCreate(name, class, parent, varargs...);
X *    WidgetSet(name, varargs);
X *    WidgetGet(name, varargs);
X *    GenericWidgetName(buf);
X *
X * This module was written by Dan Heller <island!argv@sun.com> or
X * <dheller@ucbcory.berkeley.edu>.
X *
X * The purpose of this module is to allow the programmer to Create
X * widgets and set/get widget attributes via a variable argument list
X * style of function call.  This eliminates the need for many local
X * variables and bothersome XtSetArg() calls and so forth.  An example
X * of usage:
X *
X *    Widget foo;
X *
X *    foo = WidgetCreate("foo", labelWidgetClass, toplevel,
X *        XtNlabel,		"Widget",
X *	  XtNforeground,	WhitePixelOfScreen(XtScreen(toplevel)),
X *	  XtNbackground,	BlackPixelOfScreen(XtScreen(toplevel)),
X *        XtNborderWidth,	1,
X *        NULL);
X *
X * As you can see, the list must be NULL terminated.  You may pass up to
X * to MAXARGS argument pairs.  Increase this number in WidgetWrap.h if
X * necessary.  There are special args availabel to the create/get/set
X * functions that are available:
X *
X *    XtNmanaged		pass "False" to create a non-managed widget.
X *    XtNargList		takes _two_ parameters.
X *    XtNpopupShell		pass "True" to create a PopupShellWidget.
X *    XtNapplicShell		pass "True" to create an applicationShellWidget
X *
X * The XtNargList makes it possible to pass attributes to the create/get/set
X * calls that are probably common to many widgets to be created or reset.
X *
X * static Arg args[] = {
X *     XtNforeground,	black,
X *     XtNbackground,   white,
X *     XtNwidth,	20,
X *     XtNheight,	10,
X * };
X * foo = WidgetCreate("bar", widgetClass, toplevel,
X *     XtNargList,	args, XtNumber(args),
X *     NULL);
X *
X * Most large applciations will create huge numbers of widgets which the
X * programmer has to think up unique names for all of them.  What's more,
X * typically, as noted by the examples above, the names are constant strings
X * which takes up memory, disk spaces, etc...  So, if WidgetCreate() gets
X * NULL as the name of the widget, then a widget name will be created
X * automatically.  Since most of the time, user's don't care what the name
X * of a widget is, this capability is available.
X *
X * Finally, a note about varargs.  Note that there are many different
X * implementations of varargs.  To maintain portability, it is important
X * to never return from a function that uses varargs without calling va_end().
X * va_start() and va_end() should always exist in the same block of {}'s.
X * There can be blocks between them, but va_end() shouldn't be in a block
X * inside of the va_start() stuff.  This is to allow support for weird
X * implementations which define va_start() to something like:  ".... { "
X * (pyramid computers for one).
X * Also, if you use varargs, never declare "known" arguments; extract them
X * from the vararg list later.
X */
X#include <stdio.h>
X#include <X11/Intrinsic.h>
X#include <varargs.h>
X#include "WidgetWrap.h"
X
Xchar *
XGenericWidgetName(buf)
Xchar *buf;
X{
X    static int widget_count;
X
X    (void) sprintf(buf, "_widget.%d", widget_count++);
X    return buf;
X}
X
X/*
X * WidgetCreate()
X *	Create a widget passing it's instance attributes and other parameters
X * as variable arguments.  This removes the need to build your own Arg[]
X * lists, etc...  Terminate argument list pairs with a NULL argument.
X */
X/* VARARGS */
XWidget
XWidgetCreate(va_alist)
Xva_dcl
X{
X    va_list	var;
X    Arg		args[MAXARGS];
X    int		err = 0, nargs, i = 0, managed = 1;
X    String	argstr;
X    XtArgVal	argval;
X    char	*name, buf[32];
X    WidgetClass class;
X    Widget	parent, (*create_func)() = NULL;
X
X    va_start(var);
X
X    if (!(name = va_arg(var, char *)))
X	name = GenericWidgetName(buf);
X    class = va_arg(var, WidgetClass);
X    parent = va_arg(var, Widget);
X
X    while (argstr = va_arg(var, char *)) {
X	if (i == MAXARGS) {
X	    fprintf(stderr, "WidgetCreate: too many arguments: %d\n", i);
X	    err++;
X	    break;
X	}
X	if (!strcmp(argstr, XtNargList)) {
X	    ArgList list = va_arg(var, ArgList);
X	    int numargs = va_arg(var, int);
X	    for (numargs--; i < MAXARGS && numargs >= 0; i++, numargs--)
X		XtSetArg(args[i], list[numargs].name, list[numargs].value);
X	    if (i == MAXARGS) {
X		fprintf(stderr, "WidgetCreate: too many arguments: %d\n", i);
X		err++;
X		break;
X	    }
X	} else if (!strcmp(argstr, XtNmanaged))
X	    managed = va_arg(var, int);
X	else if (!strcmp(argstr, XtNpopupShell)) {
X	    if (va_arg(var, int))
X		create_func = XtCreatePopupShell;
X	} else if (!strcmp(argstr, XtNapplicShell)) {
X	    if (va_arg(var, int))
X		create_func = XtCreateApplicationShell;
X	} else {
X	    argval = va_arg(var, XtArgVal);
X	    XtSetArg(args[i], argstr, argval);
X	    ++i;
X	}
X    }
X    va_end(var);
X
X    if (err)
X	return NULL;
X
X    if (create_func == XtCreateApplicationShell)
X	return XtCreateApplicationShell(name, class, args, i);
X
X    if (!create_func)
X	create_func = managed? XtCreateManagedWidget : XtCreateWidget;
X    return (create_func)(name, class, parent, args, i);
X}
X
X/*
X * WidgetSet()
X *	Once a widget has been created, you may use this routine to
X * add or change a varaible number of attributes on it.
X */
X/*VARARGS*/
Xvoid
XWidgetSet(va_alist)
Xva_dcl
X{
X    String   argstr;
X    Arg      args[MAXARGS];
X    XtArgVal argval;
X    int      i = 0, managed = -1;
X    va_list  var;
X    Widget   w;
X
X    va_start(var);
X
X    w = va_arg(var, Widget);
X
X    while (argstr = va_arg(var, char *)) {
X	if (i == MAXARGS) {
X	    fprintf(stderr, "Warning: increase MAXARGS! (%d)\n", i);
X	    XtSetValues(w, args, i);
X	    i = 0;
X	}
X	if (!strcmp(argstr, XtNmanaged))
X	    managed = va_arg(var, int);
X	else if (!strcmp(argstr, XtNargList)) {
X	    ArgList list = va_arg(var, ArgList);
X	    XtArgVal numargs = va_arg(var, Cardinal);
X	    XtSetValues(w, list, numargs);
X	} else {
X	    argval = va_arg(var, XtArgVal);
X	    XtSetArg(args[i], argstr, argval);
X	    ++i;
X	}
X    }
X    va_end(var);
X    if (i > 0)
X	XtSetValues(w, args, i);
X    if (managed > -1)
X	if (managed == True)
X	    XtManageChild(w);
X	else
X	    XtUnmanageChild(w);
X}
X
X/*
X * WidgetGet()
X *     Get the values of a widget via an interface identical to WidgetSet
X */
X/*VARARGS*/
Xvoid
XWidgetGet(va_alist)
Xva_dcl
X{
X    String   argstr;
X    Arg      args[MAXARGS];
X    XtArgVal argval;
X    int      i = 0;
X    va_list  var;
X    Widget   w;
X
X    va_start(var);
X
X    w = va_arg(var, Widget);
X
X    while (argstr = va_arg(var, char *)) {
X	argval = va_arg(var, XtArgVal);
X	if (i == MAXARGS) {
X	    fprintf(stderr, "Warning: increase MAXARGS! (%d)\n", i);
X	    XtGetValues(w, args, i);
X	    i = 0;
X	}
X	if (!strcmp(argstr, XtNargList)) {
X	    ArgList list = va_arg(var, ArgList);
X	    XtArgVal numargs = va_arg(var, Cardinal);
X	    XtGetValues(w, list, numargs);
X	} else
X	    XtSetArg(args[i], argstr, argval);
X        ++i;
X    }
X    va_end(var);
X    if (i > 0)
X	XtGetValues(w, args, i);
X}
+END+OF+WidgetWrap.c
echo '-rw-r--r--  1 argv         6932 Apr 20 01:46 WidgetWrap.c    (as sent)'
chmod u=rw,g=r,o=r WidgetWrap.c
ls -l WidgetWrap.c
echo x - WidgetWrap.h
sed 's/^X//' > WidgetWrap.h <<'+END+OF+WidgetWrap.h'
X/*
X * WidgetWrap.h -- header file for the WidgetWrap library.
X *
X * This module was written by Dan Heller <island!argv@sun.com> or
X * <dheller@ucbcory.berkeley.edu>.
X */
X
X#define MAXARGS		50
X#define XtNargList	"Arglist"
X#define XtNmanaged	"Managed"
X#define XtNpopupShell	"popupShell"
X#define XtNapplicShell	"applicationShell"
X
Xextern void WidgetSet(), WidgetGet();
Xextern Widget WidgetCreate();
Xextern char *GenericWidgetName();
+END+OF+WidgetWrap.h
echo '-rw-r--r--  1 argv          429 Apr 17 12:55 WidgetWrap.h    (as sent)'
chmod u=rw,g=r,o=r WidgetWrap.h
ls -l WidgetWrap.h
echo x - prompt.c
sed 's/^X//' > prompt.c <<'+END+OF+prompt.c'
X/*
X * prompt box -- display a prompt box on the screen.  Ask a question or
X * display information, etc... accepts yes/no/cancel and/or Ok as replies.
X * When the application calls the prompt box, the program "freezes" the
X * screen till the user selects one of the options available and then returns
X * to the application at the point in which the function was called.
X *
X * Because the user must reply to the question or provide some response, it
X * is important not to obscure the dialog box at all -- if it is obscured,
X * then it must raise itself back to the top of the window tree.  To do this,
X * we must get visibility notify events.  however, there is currently no
X * provision for this in the toolkit intrinsics without breaking the rule
X * of opaque data structures in object oriented programming.  Thus, we must
X * include the private header files.  Yet, even when visibility notify is
X * set to true, and we try to get the visibility notify event, we don't get
X * it!  This is probably a bug with the current intrinsics, but the code
X * remains for when/if it gets fixed.  A workaround exists by checking the
X * event types of all events (which is implemented here).
X *
X * The public routine here is PromptBox(BUTTONS, varargs)
X * The idea is to call it as:
X *    PromptBox(OK_BUTTON|CANCEL_BUTTON, "rm: remove %s?", file);
X * The return value in this case will be OK_BUTTON *or* CANCEL_BUTTON
X * depending on which the user selected.  You also have the choice of
X * YES_BUTTON and NO_BUTTON --to use more than one button, OR values together.
X *
X * To run this file as a standalone program, compile with -DPROGRAM.
X * Otherwise, this file is a module in which you can link with your
X * application to have a quick dialog box (cc -c prompt.c).  If used as
X * a library module, the only external global it requires is top_level --
X * which is a pointer to the top_level widget returned by XtInitialize().
X *
X * This file is heavily dependent on the widgetwrap code accompanying this
X * source file.  Note, if you are not on a sun workstation and not on a sys-v
X * unix box, and you *do* have vsprintf(), define -DVPRINTF when compiling.
X */
X
X#include <stdio.h>
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/Label.h>
X#include <X11/Command.h>
X#include <X11/Box.h>
X#include <X11/Form.h>
X#include <X11/Shell.h>
X#include "WidgetWrap.h"
X#include <varargs.h>
X#include <sys/stat.h>
X
X/* The following defines should exist in some header file somewhere */
X#define YES_BUTTON	1
X#define NO_BUTTON	2
X#define OK_BUTTON	4
X#define CANCEL_BUTTON	8
X
X#define SPACING(w,n)	(((w)-((n)*(WIDTH+1)))/(n+1))
X#define WIDTH		60
X
X#ifndef max
X#define max(a,b)	(((a) > (b))? (a) : (b))
X#endif /* max */
X
Xextern Widget	top_level;
Xstatic Widget	prompt_shell;
X
Xstatic int ret_value, which_buttons;
Xstatic int _do_prompt();
Xstatic Widget _build_prompt(); /* returns the transient shell created */
X
XPromptBox(va_alist)
Xva_dcl
X{
X    char	string[BUFSIZ], *fmt;
X    va_list	arg_ptr;
X
X    va_start (arg_ptr);
X
X    which_buttons = va_arg(arg_ptr, int);
X
X    fmt = va_arg (arg_ptr, char *);	/* get first arg */
X
X#if defined(sun) || defined(SYSV) || defined(VPRINTF)
X    vsprintf(string, fmt, arg_ptr);
X#else /* VPRINTF */
X    {
X	/* we're on a BSD machine that has no vsprintf() */
X	FILE foo;
X	foo._cnt = BUFSIZ;
X	foo._base = foo._ptr = string; /* may have to cast(unsigned char *) */
X	foo._flag = _IOWRT+_IOSTRG;
X	(void) _doprnt(fmt, arg_ptr, &foo);
X	*foo._ptr = '\0'; /* plant terminating null character */
X    }
X#endif /* VPRINTF */
X    va_end (arg_ptr);
X    return _do_prompt(string);
X}
X
Xstatic int
X_do_prompt(string)
XString string;
X{
X    int		width;
X    Widget	shell;
X    XEvent	event;
X
X    if (!top_level || !XtIsRealized(top_level)) {
X	fputs(string, stderr);
X	return -1; /* we haven't realized the toplevel yet! */
X    }
X
X    width = max(strlen(string) * 18, 30);
X    shell = _build_prompt(string, width);
X
X#ifdef X11R2
X    XtMoveWidget(shell,
X	(WidthOfScreen(XtScreen(shell)) - width)/2,
X	(HeightOfScreen(XtScreen(shell)) - width)/2);
X#else /* X11R2 */
X    WidgetSet(shell,
X	XtNx,	(WidthOfScreen(XtScreen(shell)) - width)/2,
X	XtNy,	(HeightOfScreen(XtScreen(shell)) - width)/2,
X	NULL);
X#endif /* X11R2 */
X
X    /* grab exclusive to disallow other windows in this application
X     * from being tampered with.
X     */
X    XtPopup(shell, XtGrabExclusive);
X
X    /*
X     * Loop here grabbing all events until the dialog box goes away.
X     * Because we've set GrabExclusive, no other windows will get
X     * events other than expose events, etc.., so we're safe.  After
X     * the popdown occurs, continue grabbing events till XtPending()
X     * says there are no more events to get because the widgets will
X     * generate Unmap events and so on.
X     */
X    for (ret_value = -1; ret_value == -1 || XtPending(); ) {
X	XtNextEvent(&event);
X	XtDispatchEvent(&event);
X	if (ret_value == -1 &&
X	    event.xany.type == VisibilityNotify &&
X	    event.xvisibility.state != VisibilityUnobscured &&
X	    event.xvisibility.window == XtWindow(shell))
X	    XMapRaised(XtDisplay(shell), XtWindow(shell));
X    }
X    return ret_value;
X}
X
Xstatic void
Xraise_prompt(w, event)
XWidget w;
XXVisibilityEvent *event;
X{
X    if (event->state != VisibilityUnobscured && ret_value == -1) {
X	XMapRaised(XtDisplay(w), XtWindow(w));
X	XFlush(XtDisplay(w));
X    }
X}
X
Xstatic void
XPopDown(w, value)
XWidget w;
Xint value;
X{
X    ret_value = value;
X    XtPopdown(prompt_shell);
X    XtDestroyWidget(prompt_shell);
X}
X
Xstatic Widget
X_build_prompt(string, width)
Xchar *string;
Xint width;
X{
X    Widget	top, box, yes, no, cancel, ok;
X    int		nbuttons = 0;
X
X    prompt_shell = WidgetCreate(NULL, transientShellWidgetClass, top_level,
X	XtNpopupShell,		True,
X	NULL);
X
X    /* this currently doesn't work, but it should */
X    {
X	XtActionsRec foo;
X
X	foo.string = "raise-prompt";
X	foo.proc = raise_prompt;
X	XtAddActions(&foo, 1);
X
X	/* prompt_shell->core.visible_interest = TRUE; */
X	XtOverrideTranslations(prompt_shell,
X	    XtParseTranslationTable("<Visible>: raise-prompt()"));
X    }
X
X    top = WidgetCreate(NULL, boxWidgetClass, prompt_shell,
X	XtNhSpace,		0,
X	XtNvSpace,		0,
X	NULL);
X
X    WidgetCreate(NULL, labelWidgetClass, top,
X	XtNlabel,		string,
X	XtNwidth,		width,
X	NULL);
X
X    if (which_buttons & YES_BUTTON)
X	nbuttons++;
X    if (which_buttons & NO_BUTTON)
X	nbuttons++;
X    if (which_buttons & OK_BUTTON)
X	nbuttons++;
X    if (which_buttons & CANCEL_BUTTON)
X	nbuttons++;
X
X    box = WidgetCreate(NULL, boxWidgetClass, top,
X	XtNfromVert,		box,
X	XtNwidth,		width,
X	XtNhSpace,		SPACING(width-3, nbuttons),
X	/* I'd like to use a gray pixmap here, but the athena box widget
X	 * will free the pixmap once this is destroyed and other widgets
X	 * that have a handle to it will die with an invalid pixmap error
X	 * if they try to use their pixmap again.
X	 */
X	/* XtNbackgroundPixmap,	XtGrayPixmap(XtScreen(top_level)), */
X	NULL);
X
X    if (which_buttons & YES_BUTTON) {
X	yes = WidgetCreate(NULL, commandWidgetClass, box,
X	    XtNwidth,		WIDTH,
X	    XtNlabel,		"Yes",
X	    NULL);
X	XtAddCallback(yes, XtNcallback, PopDown, YES_BUTTON);
X    }
X
X    if (which_buttons & NO_BUTTON) {
X	no = WidgetCreate(NULL, commandWidgetClass, box,
X	    XtNwidth,		WIDTH,
X	    XtNlabel,		"No",
X	    NULL);
X	XtAddCallback(no, XtNcallback, PopDown, NO_BUTTON);
X    }
X
X    if (which_buttons & OK_BUTTON) {
X	ok = WidgetCreate(NULL, commandWidgetClass, box,
X	    XtNwidth,		WIDTH,
X	    XtNlabel,		"Ok",
X	    NULL);
X	XtAddCallback(ok, XtNcallback, PopDown, OK_BUTTON);
X    }
X
X    if (which_buttons & CANCEL_BUTTON) {
X	cancel = WidgetCreate(NULL, commandWidgetClass, box,
X	    XtNwidth,		WIDTH,
X	    XtNlabel,		"Cancel",
X	    NULL);
X	XtAddCallback(cancel, XtNcallback, PopDown, CANCEL_BUTTON);
X    }
X
X    return prompt_shell;
X}
X
X#ifdef PROGRAM
X
XWidget top_level;
Xchar *filename;
X
X/*ARGSUSED*/
Xstatic void
Xcallback_func(w, _flags)
XWidget w;
Xcaddr_t _flags;
X{
X    char *label;
X    FILE *fp;
X    struct stat buf;
X    int flags = (int)_flags;
X
X    WidgetGet(w, XtNlabel, &label, NULL);
X
X    if (!strcmp(label, "Create")) {
X	if (stat(filename, &buf) == 0)
X	    PromptBox(OK_BUTTON, "%s already exists!", filename);
X	else if (PromptBox(flags, "Create file %s?", filename)
X		== YES_BUTTON)
X	    if ((fp = fopen(filename, "w")) == (FILE *)NULL)
X		PromptBox(OK_BUTTON, "I can't create %s.", filename);
X	    else
X		fclose(fp);
X    } else if (!strcmp(label, "Delete")) {
X	if (stat(filename, &buf) == -1)
X	    PromptBox(OK_BUTTON, "%s doesn't exist!", filename);
X	else if (PromptBox(flags, "Delete file %s?", filename)
X		== YES_BUTTON)
X	    if (unlink(filename) == -1)
X		PromptBox(OK_BUTTON, "I can't remove %s.", filename);
X    } else if (PromptBox(flags, "Really Exit?") == OK_BUTTON)
X	exit(0);
X}
X
Xmain(argc, argv)
Xunsigned int argc;
Xchar **argv;
X{
X    char trans[128], *name;
X    Widget box, w1, w2, w3;
X
X    /* initialize the toolkit and register the actions */
X    top_level = XtInitialize(*argv, *argv, NULL, 0, &argc, argv);
X
X    if (argc > 1)
X	filename = argv[1];
X    else
X	fprintf(stderr, "usage: %s filename\n", argv[0]), exit(1);
X
X    /* create the top button and its form parent */
X    box = WidgetCreate(NULL, boxWidgetClass, top_level, NULL);
X
X    w1 = WidgetCreate("button1", commandWidgetClass, box,
X	XtNlabel,		"Create",
X	XtNwidth,		200,
X	XtNheight,		30,
X	NULL);
X    XtAddCallback(w1, XtNcallback, callback_func,
X	(caddr_t)(YES_BUTTON|NO_BUTTON));
X
X    w2 = WidgetCreate("button2", commandWidgetClass, box,
X	XtNlabel,		"Delete",
X	XtNwidth,		200,
X	XtNheight,		30,
X	NULL);
X    XtAddCallback(w2, XtNcallback, callback_func,
X	(caddr_t)(YES_BUTTON|NO_BUTTON));
X
X    w3 = WidgetCreate("button3", commandWidgetClass, box,
X	XtNlabel,		"Exit",
X	XtNwidth,		200,
X	XtNheight,		30,
X	NULL);
X    XtAddCallback(w3, XtNcallback, callback_func,
X	(caddr_t)(OK_BUTTON|CANCEL_BUTTON));
X
X    XtRealizeWidget(top_level);
X    XtMainLoop();
X}
X
X#endif /* PROGRAM */
+END+OF+prompt.c
echo '-rw-r--r--  1 argv         9855 Apr 20 02:06 prompt.c    (as sent)'
chmod u=rw,g=r,o=r prompt.c
ls -l prompt.c
exit 0