/*
 * popups.c : Generic blocking popup routines
 *
 * George Ferguson, ferguson@cs.rochester.edu, 23 Apr 1993.
 */

#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Dialog.h>
extern Widget toplevel;		/* this is the only external */

/*
 * Functions defined here:
 */
Widget createPopup();				/* Generic popup routines */
void setPopupLabel();
void popupMainLoop();
void popupDone();				/* Call this when done */

static void centerWidgetAndMouse();

/*
 * Data defined here:
 */
static int popupIsDone;

/*	-	-	-	-	-	-	-	-	*/

Widget
createPopup(basename,num_buttons,callback)
char *basename;
int num_buttons;
XtCallbackProc callback;
{
    Widget shell,dialog;
    char name[256];
    int i;

    sprintf(name,"%sShell",basename);
    shell = XtCreatePopupShell(name,transientShellWidgetClass,toplevel,NULL,0);
    sprintf(name,"%sDialog",basename);
    dialog = XtCreateManagedWidget(name,dialogWidgetClass,shell,NULL,0);
    for (i=0; i < num_buttons; i++) {
	sprintf(name,"%sButton%d",basename,i);
	XawDialogAddButton(dialog,name,callback,(XtPointer)i);
    }
    XtRealizeWidget(shell);
    return(shell);
}

void
setPopupLabel(w,basename,str)
Widget w;
char *basename,*str;
{
    char name[256];
    Widget dialog;
    Arg args[1];

    sprintf(name,"%sDialog",basename);
    dialog = XtNameToWidget(w,name);
    XtSetArg(args[0],XtNlabel,str);
    XtSetValues(dialog,args,1);
}

/*
 * Popup "shell" with an exclusive grab, then dispatch events until
 * popupDone becomes True, then pop "shell" down.
 */
void
popupMainLoop(shell)
Widget shell;
{
    /* Go synchronous or the widgets don't resize properly */
    XSynchronize(XtDisplay(toplevel),True);
    /* Center the popup */
    centerWidgetAndMouse(shell,toplevel,shell);
    /* Beep */
    XBell(XtDisplay(toplevel),0);
    /* Pop it up and block until one of the buttons is clicked */
    popupIsDone = 0;
    XtPopup(shell,XtGrabExclusive);
    while (!popupIsDone) {
	/*
	 * Only dispatch XEvents since we don't want input events or
	 * timers to get in the way
	 */
	XtAppProcessEvent(XtWidgetToApplicationContext(toplevel),XtIMXEvent);
    }
    /* Okay, pop it down */
    XtPopdown(shell);
#ifndef DEBUG
    /* Back to normal */
    XSynchronize(XtDisplay(toplevel),False);
#endif
}

void
popupDone()
{
    popupIsDone = 1;
}

/*	-	-	-	-	-	-	-	-	*/
/*
 * Center widget "widget" inside widget "pwidget" and warp mouse to middle
 * of "mwidget".
 */
static void
centerWidgetAndMouse(widget,pwidget,mwidget)
Widget widget,pwidget,mwidget;
{
    Arg args[2];
    Window rwin,child;
    int x,y,px,py;
    unsigned int w,h,pw,ph,bw,d;

    /* Get child size */
    XGetGeometry(XtDisplay(widget),XtWindow(widget),
		 &rwin,&x,&y,&w,&h,&bw,&d);
    /* Get parent size, position */
    XGetGeometry(XtDisplay(pwidget),XtWindow(pwidget),
		 &rwin,&px,&py,&pw,&ph,&bw,&d);
    /* Need position in root window coords, don't ask me why */
    XTranslateCoordinates(XtDisplay(widget),XtWindow(pwidget),rwin,
			  px,py,&x,&y,&child);
    px = x;
    py = y;
    /* Compute child position */
    x = px + pw/2 - w/2;
    if (x < 0)
	x = 0;
    else if (x > WidthOfScreen(XtScreen(widget))-w)
	x = WidthOfScreen(XtScreen(widget))-w;
    y = py + ph/2 - h/2;
    if (y < 0)
	y = 0;
    else if (y > HeightOfScreen(XtScreen(widget))-h)
	y = WidthOfScreen(XtScreen(widget))-h;
    /* Set child position */
    XtSetArg(args[0],XtNx,x);
    XtSetArg(args[1],XtNy,y);
    XtSetValues(widget,args,2);
    /* Get dest size, position */
    XGetGeometry(XtDisplay(mwidget),XtWindow(mwidget),
		 &rwin,&x,&y,&w,&h,&bw,&d);
    /* Move mouse there */
    XWarpPointer(XtDisplay(mwidget),None,XtWindow(mwidget),
		 0,0,0,0,w/2,h/2);
}
