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