/* Written by Dan Heller and Paula Ferguson.  
 * Copyright 1994, O'Reilly & Associates, Inc.
 * Permission to use, copy, and modify this program without
 * restriction is hereby granted, as long as this copyright
 * notice appears in each copy of the program source code.
 * This program is freely distributable without licensing fees and
 * is provided without guarantee or warrantee expressed or implied.
 * This program is -not- in the public domain.
 */

/* working.c -- represent a complicated, time-consuming task by
 * counting from 0 to 20000 and provide feedback to the user about
 * how far we are in the process.  The user may terminate the process
 * at any time by selecting the Stop button in the WorkingDialog.
 * This demonstrates how a WorkingDialog can be used to allow the
 * user to interrupt lengthy procedures.
 */
#include <Xm/MessageB.h>
#include <Xm/PushB.h>

#define MAXNUM 20000

void done();

/* Global variables */
static int           i = 0;
static XtWorkProcId  work_id;

main(argc, argv)
int argc;
char *argv[];
{
    XtAppContext  app;
    Widget        toplevel, button;
    XmString      label;
    void          pushed();

    XtSetLanguageProc (NULL, NULL, NULL);

    toplevel = XtVaAppInitialize (&app, "Demos",
        NULL, 0, &argc, argv, NULL, NULL);

    label = XmStringCreateLocalized ("Press Here To Start A Long Task");
    button = XtVaCreateManagedWidget ("button",
        xmPushButtonWidgetClass, toplevel,
        XmNlabelString,          label,
        NULL);
    XtAddCallback (button, XmNactivateCallback, pushed, app);
    XmStringFree (label);

    XtRealizeWidget (toplevel);
    XtAppMainLoop (app);
}

/* pushed() -- the callback routine for the main app's pushbutton. */
void
pushed(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
    XtAppContext  app = (XtAppContext) client_data;
    Widget        dialog;
    XmString      stop_txt;
    Arg           args[5];
    int           n;
    Boolean       count();

    /* Create the dialog -- the "cancel" button says "Stop" */
    n = 0;
    stop_txt = XmStringCreateLocalized ("Stop");
    XtSetArg(args[n], XmNcancelLabelString, stop_txt); n++;
    dialog = XmCreateWorkingDialog (w, "working", args, n);
    XmStringFree (stop_txt);

    work_id = XtAppAddWorkProc (app, count, dialog);

    XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON));
    XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));

    /* Use cancel button to stop counting. True = remove work proc */
    XtAddCallback (dialog, XmNcancelCallback, done, (XtPointer)True);

    XtManageChild (dialog);
    XtPopup (XtParent (dialog), XtGrabNone);
}

/* count() -- work procedure that counts to MAXNUM.  When we get there,
 * change the "Stop" button to say "Done".
 */
Boolean
count(client_data)
XtPointer client_data;
{
    Widget dialog = (Widget) client_data;
    char buf[64];
    XmString str, button;
    Boolean finished = False;

    /* If we printed every number, the flicker is too fast to read.
     * Therefore, just print every 1000 ticks for smoother feedback.
     */
    if (++i % 1000 != 0)
        return finished;

    /* display where we are in the counter. */
    sprintf (buf, "Counter: %d", i);
    str = XmStringCreateLocalized (buf);
    XtVaSetValues (dialog, XmNmessageString, str, NULL);
    XmStringFree (str);

    if (i == MAXNUM) {
        i = 0;
        finished = True;
        button = XmStringCreateLocalized ("Done");
        XtVaSetValues (dialog, XmNcancelLabelString, button, NULL);
        XmStringFree (button);
        XtRemoveCallback (dialog, XmNcancelCallback, done, (XtPointer)True);
        XtAddCallback (dialog, XmNcancelCallback, done, (XtPointer)False);
        XMapRaised (XtDisplay (dialog), XtWindow (XtParent (dialog)));
    }

    /* Return either True, meaning we're done and remove the work proc,
     * or False, meaning continue working by calling this function. 
     */
    return finished;
}

/* done () -- user pressed "Stop" or "Done" in WorkingDialog. */
void
done(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
    Boolean remove_work_proc = (Boolean) client_data;

    if (remove_work_proc) {
        i = 0;
        XtRemoveWorkProc (work_id);
    }
    XtDestroyWidget (dialog);
}