[comp.windows.open-look] Requests for sample code.....

kbj@jupiter.risc.com (Ken Johnson) (11/13/90)

Howdy Users of XView,

Due to the tremendous number of requests for information on handling compute 
intensive tasks and panels I have enclosed a copy of code that will basically 
get one started on the road to interactive window management when faced by nasty
compute intensive routines that shut down your window management.  The
basic needs are a compute routine that calls XServer every once in a while and
the proper dispatching of the compute intensive routine.  A description 
of what is here is contained in O'Reilly Vol. 7 in section 19.10.

The code doesn't compile because its got a lot of lose threads hanging around.
Pay attention to the end of main, XServer, RunProc, Compute, and the callback
routines PauseProc, etc.

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

Ken Johnson                             Phone: 805-373-4487
Rockwell International Science Center   Comnet: 273-4487
1049 Camino Dos Rios A-18               e-mail: kbj@risc.com
Thousand Oaks, CA 91360

       If enough data is collected
                     anything may be proven by statistical methods....

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

/* openlook_dispatch demonstrates the use of notify_dispatch for
   handling panel and frame events during compute intensive routines. 

   Panel items to pause, stop, single step, and stop the computing
   are provided.

   If anyone has suggestions or improvements please comment.

   The application is pared down to the bare minimum. */

/* ------ main includes ------ */

#include <stdlib.h>

#include <X11/Xlib.h>

#include <xview/xview.h>
#include <xview/frame.h>

#include "datastruct.h"       /* my own data stuff that you don't need */

/* ------ Globals ------ */

	Frame frame;               /* main frame */
    Display *dpy;

#define SERVICE_HALT 1

/* ------ Functions ------ */

void PauseProc();              /* panel button proc */
void ContProc();
void StopProc();
void StepProc();

/* ------ */

void QuitProc();               /* menu callbacks */
void RunProc();

/* ------ */

int XService();                /* flag and dispatch handler */

/* ------ main ------ */

void main(argc, argv)
	int argc;
	char *argv[];
{
	Panel MainPanel;                 /* main panel */
	Menu  menu;

	/* ------ initialization ------ */

	xv_init(XV_INIT_ARGC_PTR_ARGV,
			&argc, argv, NULL);

	frame = (Frame) xv_create(NULL, FRAME,
							  FRAME_LABEL, InputFileName,
							  FRAME_SHOW_HEADER, TRUE, 
							  FRAME_INHERIT_COLORS, TRUE,
							  FRAME_NO_CONFIRM, FALSE,
							  NULL);

	/* ------ init global display var ------ */

	dpy = (Display *) xv_get(frame, XV_DISPLAY);

	/* ------ install menus in panel ------ */

	MainPanel = (Panel) xv_create(frame, PANEL, NULL); 

	xv_set(MainPanel,
		   WIN_FIT_HEIGHT, 0,
		   WIN_FIT_WIDTH, 0, 
		   WIN_ROW_GAP, 20,
		   WIN_COLUMN_GAP, 60,
		   NULL);
	
	/* ------ */

	menu = (Menu) xv_create(NULL, MENU,
							MENU_TITLE_ITEM, "File operations",
							MENU_ACTION_ITEM, "Quit", QuitProc,
							MENU_ACTION_ITEM, "Run", RunProc,
							NULL);
	
	(void) xv_create(MainPanel, PANEL_BUTTON,
					 PANEL_LABEL_STRING, "File",
					 PANEL_ITEM_MENU, menu,
					 XV_X, xv_col(MainPanel, 0),
					 XV_Y, xv_row(MainPanel, 0),
					 NULL);
	
	/* ------ install panel buttons ------ */

	(void) xv_create(MainPanel, PANEL_BUTTON,                /* Pause */
					 PANEL_LABEL_STRING, "Pause",
					 PANEL_NOTIFY_PROC, PauseProc,
					 XV_X, xv_col(MainPanel, 0),
					 XV_Y, xv_row(MainPanel, 1),
					 NULL);
	
	(void) xv_create(MainPanel, PANEL_BUTTON,               /* Continue */
					 PANEL_LABEL_STRING, "Continue",
					 PANEL_NOTIFY_PROC, ContProc,
					 XV_X, xv_col(MainPanel, 1),
					 XV_Y, xv_row(MainPanel, 1),
					 NULL);
	
	(void) xv_create(MainPanel, PANEL_BUTTON,               /* Stop */
					 PANEL_LABEL_STRING, "Stop",
					 PANEL_NOTIFY_PROC, StopProc,
					 XV_X, xv_col(MainPanel, 0),
					 XV_Y, xv_row(MainPanel, 2),
					 NULL);

	(void) xv_create(MainPanel, PANEL_BUTTON,               /* Step */
					 PANEL_LABEL_STRING, "Step",
					 PANEL_NOTIFY_PROC, StepProc,
					 XV_X, xv_col(MainPanel, 1),
					 XV_Y, xv_row(MainPanel, 2),
					 NULL);

	window_fit(MainPanel);
	
	/* ------ resize the menu panel ------ */

	window_fit(frame);

    /* ------ dispatch the application ------ */

	/* This is a rather strange construct.  The application toggles
	   between two different event handlers.  xv_main_loop handles
	   all events when normal operations are in effect.  However,
	   the main compute routine compute takes a while to run.  If it
	   is launched from a menu or button callback procedure it
	   will halt event handling until it returns and allows the
	   callback to return to xv_main_loop.

	   To handle this when a compute intensive routine is to be
	   run it must assume dispatch control by halting xv_main_loop
	   and periodically checking the occurance of events by calling
	   XService.  This is done by halting xv_main_loop from the callback and
	   returning. This pops us out of xv_main_loop thereby allowing
	   the compute intensive routine to take control.  The compute
	   routine checks XService and lets compute run as long as
	   PAUSE is not set. This can be done by any callback process
	   serviced from XService.  When PAUSE is set XService continues
	   to handle events until PAUSE is reset. */

	while (TRUE) {
		xv_main_loop(frame);
		Compute();
	}
}

/* ------ MENU DRIVEN OPERATIONS ------ */

/* These routines are callbacks from menu action items */

/* ------ QuitProc ------ */

void QuitProc(item, event)
	Panel_item item;
	Event event;
{
	xv_destroy_safe(frame);
}

/* ------ RunProc ------ */

/* To run the compute routine and handle events you must
   halt xv_main_loop.  The infinite loop at the end of main
   returns from xv_main_loop and drops into the compute routine
   which handles its own event dispatching */

void RunProc(item, event)
	Panel_item item;
	Event event;
{
	notify_stop();
}
/* ------ Panel button processes ------ */

/* There routines handle the panel buttons that control the
   compute process */

/* ------ PauseProc ------ */

/* PAUSE causes XService to poll events until
   PAUSE is reset */

void PauseProc()
{
	PAUSE = TRUE;
}

/* ------ ContProc ------ */

/* Continue resets PAUSE and cancels the single step */

void ContProc()
{
	PAUSE = FALSE;
	STEP = FALSE ;
}

/* ------ StepProc ------ */

/* Step causes the program to single step */

void StepProc()
{
	PAUSE = FALSE;
	STEP = TRUE;
}

/* ------ StopProc ------ */

/* Dump out of the compute routine */

void StopProc()
{
	STOP = TRUE;
	
	PAUSE = FALSE;
	STEP = FALSE;
}

/* ------ XService ------ */

/* service the main event loop from the computation 
   routine.  Wait here if PAUSE is set. The routines returns
   TRUE if the compute process is to stop.  Handling a stop is
   up to the compute routine. */

int XService()
{

	if (batch == TRUE) {        /* During batch there is no X interface */
		return FALSE;
	}

	/* ------ */

	/* This will allow the handler to check and see if the user's
	   hit a compute process control button */

	notify_dispatch();          /* Check events */
	XFlush(dpy);

	/* ------ */

	while (PAUSE == TRUE) {     /* PAUSE until set to FALSE */
		notify_dispatch();
		XFlush(dpy);
	}

	/* ------ */

	/* resetting step will accomplish the following.

	   - if PAUSE is still set the event will be caught above
	   - if CONT is hit PAUSE and STEP will be reset
	   - hitting step will cause and event which will reset */

	if (STEP == TRUE) {
		STEP = FALSE;
		PAUSE = TRUE;
	}

	/* ------ */

	if (STOP == TRUE) {         /* if STOP was set tell ntwrk21 to exit */

		PAUSE = FALSE;
		STEP = FALSE;
		STOP = FALSE;

		return SERVICE_HALT;
	}
	else
		return FALSE;
}

/* ------ Compute Routine ------ */


/*	Compute - this routine does absolutely nothing but waste time */

void Compute()
{
	int i, j, k, n;

	/* ------ get lost for a long period of time ------ */
	
	for (k = 0; k < 1000; k++) { 

		/* ------ service X ------ */

		if (XService() == XSERVICE_HALT) {
			return;
		}

		/* ------ waste more time ------ */

		for (i = 0; i < 1000; i++) {
			a = sin(2.0 * 3.1415 * ((double) j / 100.0));
		}
	}
}