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));
}
}
}