/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "defines.h" #include "Strings.h" #include "DXExecCtl.h" #include "Command.h" #include "DXApplication.h" #include "DXPacketIF.h" #include "List.h" #include "ListIterator.h" #include "Network.h" #include "SequencerNode.h" #include "ErrorDialogManager.h" #include "ProcessGroupManager.h" #include "../widgets/VCRControl.h" DXExecCtl::DXExecCtl() { this->forceNetworkResend = TRUE; this->forceParameterResend = TRUE; this->execOnChange = FALSE; this->execOnChangeSuspensions = 0; this->isCurrentlyExecuting = FALSE; this->vcrIsExecuting = FALSE; this->resumeExecOnChangeAfterExecution = FALSE; this->endExecOnChangePending = FALSE; } void DXExecCtl::forceFullResend() { this->forceNetworkResend = TRUE; this->forceParameterResend = TRUE; #if WORKSPACE_PAGES GroupManager *pmgr = (GroupManager*) theDXApplication->network->getGroupManagers()->findDefinition (PROCESS_GROUP); if (pmgr) pmgr->setDirty(); #else if(theDXApplication->PGManager) theDXApplication->PGManager->setDirty(); #endif SequencerNode* sequencer = theDXApplication->network->sequencer; if(sequencer) sequencer->transmitted = FALSE; } void DXExecCtl::BGBeginMessage(void *clientData, int id, void *p) { DXExecCtl *ctl = (DXExecCtl *)clientData; ctl->beginSingleExecution(FALSE); } void DXExecCtl::BGEndMessage(void *clientData, int id, void *p) { DXExecCtl *ctl = (DXExecCtl *)clientData; ctl->endLastExecution(!ctl->vcrIsExecuting); } void DXExecCtl::HWBeginMessage(void *clientData, int id, void *p) { DXExecCtl *ctl = (DXExecCtl *)clientData; if (!ctl->hwExecuting++ AND !ctl->isExecuting()) theDXApplication->notifyClients(DXApplication::MsgExecute); } void DXExecCtl::HWEndMessage(void *clientData, int id, void *p) { DXExecCtl *ctl = (DXExecCtl *)clientData; Symbol msg = 0; ASSERT(ctl->hwExecuting > 0); if (--ctl->hwExecuting <= 0 AND !ctl->isExecuting()) msg = ctl->inExecOnChange() ? DXApplication::MsgStandBy : DXApplication::MsgExecuteDone; #ifdef SET_HW_BUSY_CURSOR if (ctl->hwExecuting <= 0 AND ctl->hwBusy) { theDXApplication->setBusyCursor(FALSE); ctl->hwBusy = FALSE; } #endif if (msg) theDXApplication->notifyClients(msg); } void DXExecCtl::ExecComplete(void *clientData, int id, void *p) { DXExecCtl *ctl = theDXApplication->getExecCtl(); SequencerNode* sequencer = theDXApplication->network->sequencer; // // During VCR executing we turn off green lights and pop up // the Play button ONLY when we receive "stop" command. // if (ctl->vcrIsExecuting AND !EqualString((char*)p, "stop")) return; ctl->endLastExecution(TRUE); if (ctl->vcrIsExecuting) { if (sequencer) sequencer->setPlayDirection(SequencerNode::Directionless); ctl->vcrIsExecuting = FALSE; } if (!ctl->inExecOnChange() AND ctl->hwExecuting <= 0) theDXApplication->notifyClients(DXApplication::MsgExecuteDone); // else // MsgStandBy already sent by endLastExecution() } void DXExecCtl::ResumeExecOnChange(void *clientData, int id, void *p) { DXExecCtl *ctl = theDXApplication->getExecCtl(); if(ctl->isExecOnChangeSuspended()) ctl->resumeExecOnChange(); } void DXExecCtl::newConnection() { DXPacketIF *p = theDXApplication->getPacketIF(); ASSERT(p); p->setHandler(DXPacketIF::INTERRUPT, DXExecCtl::ExecComplete, (void*)theDXApplication->getExecCtl(), "stop"); // // highlighting handlers for HW rendering // this->hwExecuting = 0; this->hwBusy = FALSE; p->setHandler(DXPacketIF::INFORMATION, DXExecCtl::HWBeginMessage, (void *)this, "HW: begin"); p->setHandler(DXPacketIF::INFORMATION, DXExecCtl::HWEndMessage, (void *)this, "HW: end"); p->setHandler(DXPacketIF::INFORMATION, DXExecCtl::BGBeginMessage, (void *)this, "BG: begin"); p->setHandler(DXPacketIF::INFORMATION, DXExecCtl::BGEndMessage, (void *)this, "BG: end"); SequencerNode* sequencer = theDXApplication->network->sequencer; if (sequencer) sequencer->transmitted = FALSE; if (this->inExecOnChange()) { this->updateMacros(TRUE); this->resumeExecOnChange(); } this->execOnChange = FALSE; // Avoid a resumeExecOnChange() this->endLastExecution(FALSE); this->forceNetworkResend = TRUE; this->forceParameterResend = TRUE; this->execOnChangeSuspensions = 0; this->isCurrentlyExecuting = FALSE; this->vcrIsExecuting = FALSE; } void DXExecCtl::updateMacros(boolean force) { DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) return; boolean forcenet = force || this->forceNetworkResend; boolean forceparam = force || this->forceParameterResend; boolean resume = FALSE; if (this->inExecOnChange() AND !this->isExecOnChangeSuspended()) { this->suspendExecOnChange(); resume = TRUE; } this->forceNetworkResend = FALSE; this->forceParameterResend = FALSE; #if WORKSPACE_PAGES ProcessGroupManager *pmgr = (ProcessGroupManager*) theDXApplication->network->getGroupManagers()->findDefinition (PROCESS_GROUP); if(pmgr AND pmgr->isDirty()) pmgr->sendAssignment(ProcessGroupManager::ATTACH); #else if(theDXApplication->PGManager AND theDXApplication->PGManager->isDirty()) theDXApplication->PGManager-> sendAssignment(ProcessGroupManager::ATTACH); #endif ListIterator ii(theDXApplication->macroList); Network *n; while((n = (Network*)ii.getNext()) != NULL) { boolean dirty = n->isDirty(); if (forcenet || dirty) n->sendNetwork(); if (forceparam || dirty) n->sendValues(forceparam); } n = theDXApplication->network; boolean dirty = n->isDirty(); if (forcenet || dirty) n->sendNetwork(); if (forceparam || dirty) n->sendValues(forceparam); SequencerNode* sequencer = n->sequencer; if (sequencer && (force || NOT sequencer->transmitted)) this->vcrTransmit(); if (resume) this->resumeExecOnChange(); } void DXExecCtl::vcrFrameSet(char* command) { DXPacketIF *p = theDXApplication->getPacketIF(); void (*callback)(void*,int,void*) = NULL; if (p != NULL) { if(this->inExecOnChange()) { this->suspendExecOnChange(); callback = ResumeExecOnChange; } p->send(DXPacketIF::FOREGROUND, command, callback); } } void DXExecCtl::vcrTransmit() { char command[1024]; DXPacketIF *p = theDXApplication->getPacketIF(); SequencerNode* vcr = theDXApplication->network->sequencer; if (p == NULL) return; sprintf(command, "sequence %s();\n", theDXApplication->network->getNameString()); p->send(DXPacketIF::FOREGROUND, command); char *s = vcr->getFrameControlString(); p->send(DXPacketIF::FOREGROUND, s); delete s; p->send(DXPacketIF::FOREGROUND, vcr->isLoopMode() ? "loop on;\n" : "loop off;\n"); p->send(DXPacketIF::FOREGROUND, vcr->isPalindromeMode() ? "palindrome on;\n" : "palindrome off;\n"); vcr->transmitted = TRUE; } void DXExecCtl::vcrExecute(int action) { SequencerNode* sequencer = theDXApplication->network->sequencer; DXPacketIF *p = theDXApplication->getPacketIF(); if (NOT p OR this->vcrIsExecuting OR this->isCurrentlyExecuting ) { SequencerDirection direction; if(NOT p) ErrorMessage("No Connection to the server."); else ErrorMessage("The program is currently executing."); if (action == VCR_FORWARD) direction = (p AND this->vcrIsExecuting ? SequencerNode::BackwardDirection : SequencerNode::Directionless); else direction = (p AND this->vcrIsExecuting ? SequencerNode::ForwardDirection : SequencerNode::Directionless); sequencer->setPlayDirection(direction); return; } this->vcrIsExecuting = TRUE; this->beginSingleExecution(TRUE); // May suspend ExecOnChange. p->send(DXPacketIF::FOREGROUND, action==VCR_FORWARD ? "forward;\n" : "backward;\n"); p->send(DXPacketIF::FOREGROUND, sequencer->isStepMode() ? "step;\n" : "play;\n"); } void DXExecCtl::vcrCommand(int action, boolean pressed) { char command[30]; DXPacketIF *p = theDXApplication->getPacketIF(); SequencerNode* sequencer = theDXApplication->network->sequencer; Widget vcr = NULL; void (*callback)(void*,int,void*); boolean doEnd = FALSE; if (action == VCR_STOP) { ASSERT(sequencer); vcr = sequencer->getVCRWidget(); } if (p == NULL) { // this->endLastExecution(!this->vcrIsExecuting); this->vcrIsExecuting = FALSE; sequencer->setPlayDirection(SequencerNode::Directionless); if (action == VCR_STOP) XtVaSetValues(vcr, XmNnext, sequencer->next, NULL); return; } callback = NULL; switch(action) { case VCR_PALINDROME: sequencer->setPalindromeMode(pressed); strcpy(command, pressed ? "palindrome on;\n" : "palindrome off;\n"); break; case VCR_STEP: sequencer->setStepMode(pressed); sequencer->setPlayDirection(SequencerNode::Directionless); strcpy(command, "pause;\n"); doEnd = this->vcrIsExecuting; this->vcrIsExecuting = FALSE; break; case VCR_LOOP: sequencer->setLoopMode(pressed); strcpy(command, pressed ? "loop on;\n" : "loop off;\n"); break; case VCR_PAUSE: strcpy(command, "pause;\n"); doEnd = this->vcrIsExecuting; this->vcrIsExecuting = FALSE; sequencer->setPlayDirection(SequencerNode::Directionless); break; case VCR_STOP: strcpy(command, "stop;\n"); doEnd = this->vcrIsExecuting; this->vcrIsExecuting = FALSE; sequencer->setPlayDirection(SequencerNode::Directionless); break; default: ASSERT(FALSE); } p->send(DXPacketIF::FOREGROUND,command); if (action == VCR_STOP) { sequencer->next = sequencer->getStartValue(); sprintf(command, "@nextframe = %d;\n", sequencer->next); if(this->inExecOnChange() AND !this->isExecOnChangeSuspended()) this->suspendExecOnChange(); p->send(DXPacketIF::FOREGROUND, command, ResetVcrNextFrame); } if (doEnd) this->endLastExecution(action != VCR_STOP); } void DXExecCtl::ResetVcrNextFrame(void *clientData, int id, void *p) { DXExecCtl *ctl = theDXApplication->getExecCtl(); SequencerNode* sequencer = theDXApplication->network->sequencer; ASSERT(sequencer); Widget vcr = sequencer->getVCRWidget(); sequencer->next = sequencer->getStartValue(); XtVaSetValues(vcr, XmNnext, sequencer->next, NULL); if(ctl->isExecOnChangeSuspended()) ctl->resumeExecOnChange(); } void DXExecCtl::enableExecOnChange() { DXPacketIF *p = theDXApplication->getPacketIF(); if (!p || this->execOnChange) return; // // Set the light green now, so that sending big networks looks like // execution. // theDXApplication->notifyClients(DXApplication::MsgExecute); // // Update macros here and not in beginSingleExecution() so that // execOnChange doesn't get suspended. // this->updateMacros(); this->execOnChange = TRUE; // // Go into exec on change mode. // this->resumeExecOnChange(); // // Do what is usually necessary at the beginning of an execution. // this->beginSingleExecution(FALSE); // updateMacros done above // // Now cause the first execution. // char s[100]; strcpy(s, theDXApplication->network->getNameString()); strcat(s, "();\n"); p->send(DXPacketIF::FOREGROUND, s, DXExecCtl::ExecComplete, NULL); } // // Go out of execution on change mode without terminating the current // graph execution. If not current executing, then we go ahead and // go out of eoc mode, otherwise schedule the exit from eoc mode for // the end of the current graph execution (see endLastExecution()). // We return TRUE if we were able to go out of eoc mode now, FALSE if // we won't be going out until the end of the current execution. // boolean DXExecCtl::endExecOnChange() { if (!this->inExecOnChange()) return TRUE; // // If the exec is currently executing, then we will wait to go out // of execute-on-change mode until the current execution completes. // If we don't do this, then the INTERRUPT message to go out of // execute on change, will also kill the current graph execution, // which we don't want to do. // if (this->isCurrentlyExecuting) { this->endExecOnChangePending = TRUE; return FALSE; } if (this->vcrIsExecuting) { this->vcrIsExecuting = FALSE; // Only do one endLastExecution(). this->vcrCommand(VCR_PAUSE, 0); } this->endExecOnChangePending = FALSE; this->execOnChangeSuspensions = 0; this->execOnChange = FALSE; DXPacketIF *p = theDXApplication->getPacketIF(); if (p) p->send(DXPacketIF::INTERRUPT); theDXApplication->notifyClients(DXApplication::MsgExecuteDone); return TRUE; } void DXExecCtl::suspendExecOnChange() { if (!this->inExecOnChange()) return; if (this->execOnChangeSuspensions == 1) return; // Already suspended this->execOnChangeSuspensions = 1; DXPacketIF *p = theDXApplication->getPacketIF(); if (p) { p->send(DXPacketIF::INTERRUPT); p->sendImmediate("sync"); } } void DXExecCtl::resumeExecOnChange() { this->execOnChangeSuspensions = 0; #if 00 if (!this->inExecOnChange() || this->isExecuting()) return; DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) return; #else DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) return; if (!this->inExecOnChange()) return; if (this->isExecuting()) { this->resumeExecOnChangeAfterExecution = TRUE; this->execOnChangeSuspensions = 1; return; } #endif // // Be sure that all pending assignments/definitions are processed by // the executive before going into execute on change. If we don't do // this we can get multiple executions from the pending assigments. // Note that this an unneeded '$sync' is sent when we are in execute- // on-change and the user does an 'execute-once' command. In this // case we still send the '$sync', but it is not necessary. // p->sendImmediate("sync"); char s[100]; strcpy(s, theDXApplication->network->getNameString()); strcat(s, "();\n"); p->send(DXPacketIF::BACKGROUND, s); theDXApplication->notifyClients(DXApplication::MsgStandBy); } void DXExecCtl::executeOnce() { DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) return; #if 0 if (this->inExecOnChange()) this->suspendExecOnChange(); #endif this->beginSingleExecution(TRUE); char s[100]; strcpy(s, theDXApplication->network->getNameString()); strcat(s, "();\n"); p->send(DXPacketIF::FOREGROUND, s, DXExecCtl::ExecComplete, NULL); } void DXExecCtl::terminateExecution() { #ifdef SET_HW_BUSY_CURSOR if (this->hwExecuting > 0 AND NOT this->hwBusy) { theDXApplication->setBusyCursor(TRUE); this->hwBusy = TRUE; } #endif if (!this->isCurrentlyExecuting && !this->execOnChange) return; if (this->vcrIsExecuting) { this->vcrIsExecuting = FALSE; // Only do one endLastExecution(). this->vcrCommand(VCR_PAUSE, 0); } Symbol msg; DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) { msg = DXApplication::MsgExecuteDone; // // Set activation of execution dependent commands. // theDXApplication->notExecutingCmd->execute(); } else { msg = 0; p->send(DXPacketIF::INTERRUPT); p->send(DXPacketIF::FOREGROUND, "Executive(\"nop\");", DXExecCtl::ExecComplete, NULL); p->sendImmediate("sync"); theDXApplication->executeOnChangeCmd->activate(); } this->execOnChange = FALSE; // FIXME: should use the following but won't right before release... this->isCurrentlyExecuting = FALSE; if (msg) theDXApplication->notifyClients(msg); } void DXExecCtl::updateMacro(Network *n) { DXPacketIF *p = theDXApplication->getPacketIF(); if (p == NULL) return; boolean resume = FALSE; if (n->isDirty()) { if (this->inExecOnChange() AND !this->isExecOnChangeSuspended()) { this->suspendExecOnChange(); resume = TRUE; } n->sendNetwork(); n->sendValues(); if (resume) this->resumeExecOnChange(); } } // // This function is called with a boolean that, in essence, indicates // whether the system is quiescent (updateable) or active (i.e. as a // result of the BG: begin message, and thus not updateable). void DXExecCtl::beginSingleExecution(boolean update) { theDXApplication->notifyClients(DXApplication::MsgExecute); if (update && this->inExecOnChange() && !this->isExecOnChangeSuspended()) this->suspendExecOnChange(); SequencerNode* sequencer = theDXApplication->network->sequencer; theDXApplication->clearErrorList(); if (update) this->updateMacros(); this->isCurrentlyExecuting = TRUE; // // Set activation of execution dependent commands. // theDXApplication->executingCmd->execute(); } void DXExecCtl::endLastExecution(boolean resume) { this->isCurrentlyExecuting = FALSE; SequencerNode* sequencer = theDXApplication->network->sequencer; Symbol msg = 0; if (this->vcrIsExecuting) { if (sequencer->isStepMode()) this->vcrIsExecuting = FALSE; } if ((resume || this->resumeExecOnChangeAfterExecution) AND this->isExecOnChangeSuspended()) { this->resumeExecOnChange(); // This may result in MsgStandBy message } else if (this->inExecOnChange() && !this->isExecOnChangeSuspended()) { if (this->hwExecuting <= 0) msg = DXApplication::MsgStandBy; } // // If a request to exit ExecOnChange mode was requested during an // execution, then do it now. // if (this->endExecOnChangePending) { this->endExecOnChangePending = FALSE; this->endExecOnChange(); msg = 0; } this->resumeExecOnChangeAfterExecution = FALSE; // // Set activation of execution dependent commands. // theDXApplication->notExecutingCmd->execute(); // // Indicate the nodes that had errors. // FIXME: only do this if there are errors. // theDXApplication->refreshErrorIndicators(); if (msg) theDXApplication->notifyClients(msg); }