1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8
9 #include <dxconfig.h>
10 #include "../base/defines.h"
11
12
13 #include "DXStrings.h"
14 #include "DXExecCtl.h"
15 #include "Command.h"
16 #include "DXApplication.h"
17 #include "DXPacketIF.h"
18 #include "List.h"
19 #include "ListIterator.h"
20 #include "Network.h"
21 #include "SequencerNode.h"
22 #include "ErrorDialogManager.h"
23 #include "ProcessGroupManager.h"
24 #include "../widgets/VCRControl.h"
25
26
DXExecCtl()27 DXExecCtl::DXExecCtl()
28 {
29 this->forceNetworkResend = TRUE;
30 this->forceParameterResend = TRUE;
31 this->execOnChange = FALSE;
32 this->execOnChangeSuspensions = 0;
33 this->isCurrentlyExecuting = FALSE;
34 this->vcrIsExecuting = FALSE;
35 this->resumeExecOnChangeAfterExecution = FALSE;
36 this->endExecOnChangePending = FALSE;
37 }
38
39 void
forceFullResend()40 DXExecCtl::forceFullResend()
41 {
42 this->forceNetworkResend = TRUE;
43 this->forceParameterResend = TRUE;
44
45 #if WORKSPACE_PAGES
46 GroupManager *pmgr = (GroupManager*)
47 theDXApplication->network->getGroupManagers()->findDefinition (PROCESS_GROUP);
48 if (pmgr) pmgr->setDirty();
49 #else
50 if(theDXApplication->PGManager)
51 theDXApplication->PGManager->setDirty();
52 #endif
53
54 SequencerNode* sequencer = theDXApplication->network->sequencer;
55 if(sequencer)
56 sequencer->transmitted = FALSE;
57 }
58
59 void
BGBeginMessage(void * clientData,int id,void * p)60 DXExecCtl::BGBeginMessage(void *clientData, int id, void *p)
61 {
62 DXExecCtl *ctl = (DXExecCtl *)clientData;
63 ctl->beginSingleExecution(FALSE);
64 }
65 void
BGEndMessage(void * clientData,int id,void * p)66 DXExecCtl::BGEndMessage(void *clientData, int id, void *p)
67 {
68 DXExecCtl *ctl = (DXExecCtl *)clientData;
69 ctl->endLastExecution(!ctl->vcrIsExecuting);
70 }
71
72 void
HWBeginMessage(void * clientData,int id,void * p)73 DXExecCtl::HWBeginMessage(void *clientData, int id, void *p)
74 {
75 DXExecCtl *ctl = (DXExecCtl *)clientData;
76
77 if (!ctl->hwExecuting++ AND !ctl->isExecuting())
78 theDXApplication->notifyClients(DXApplication::MsgExecute);
79 }
80 void
HWEndMessage(void * clientData,int id,void * p)81 DXExecCtl::HWEndMessage(void *clientData, int id, void *p)
82 {
83 DXExecCtl *ctl = (DXExecCtl *)clientData;
84 Symbol msg = 0;
85 ASSERT(ctl->hwExecuting > 0);
86
87 if (--ctl->hwExecuting <= 0 AND !ctl->isExecuting())
88 msg = ctl->inExecOnChange() ? DXApplication::MsgStandBy :
89 DXApplication::MsgExecuteDone;
90 #ifdef SET_HW_BUSY_CURSOR
91 if (ctl->hwExecuting <= 0 AND ctl->hwBusy)
92 {
93 theDXApplication->setBusyCursor(FALSE);
94 ctl->hwBusy = FALSE;
95 }
96 #endif
97
98 if (msg)
99 theDXApplication->notifyClients(msg);
100 }
101
102 void
ExecComplete(void * clientData,int id,void * p)103 DXExecCtl::ExecComplete(void *clientData, int id, void *p)
104 {
105
106 DXExecCtl *ctl = theDXApplication->getExecCtl();
107 SequencerNode* sequencer = theDXApplication->network->sequencer;
108
109 //
110 // During VCR executing we turn off green lights and pop up
111 // the Play button ONLY when we receive "stop" command.
112 //
113 if (ctl->vcrIsExecuting AND !EqualString((char*)p, "stop"))
114 return;
115
116 ctl->endLastExecution(TRUE);
117
118 if (ctl->vcrIsExecuting)
119 {
120 if (sequencer)
121 sequencer->setPlayDirection(SequencerNode::Directionless);
122 ctl->vcrIsExecuting = FALSE;
123 }
124
125 if (!ctl->inExecOnChange() AND ctl->hwExecuting <= 0)
126 theDXApplication->notifyClients(DXApplication::MsgExecuteDone);
127 // else
128 // MsgStandBy already sent by endLastExecution()
129 }
130
131 void
ResumeExecOnChange(void * clientData,int id,void * p)132 DXExecCtl::ResumeExecOnChange(void *clientData, int id, void *p)
133 {
134
135 DXExecCtl *ctl = theDXApplication->getExecCtl();
136 if(ctl->isExecOnChangeSuspended())
137 ctl->resumeExecOnChange();
138 }
139
newConnection()140 void DXExecCtl::newConnection()
141 {
142 DXPacketIF *p = theDXApplication->getPacketIF();
143
144 ASSERT(p);
145
146 p->setHandler(DXPacketIF::INTERRUPT,
147 DXExecCtl::ExecComplete,
148 (void*)theDXApplication->getExecCtl(),
149 "stop");
150
151 //
152 // highlighting handlers for HW rendering
153 //
154 this->hwExecuting = 0;
155 this->hwBusy = FALSE;
156 p->setHandler(DXPacketIF::INFORMATION,
157 DXExecCtl::HWBeginMessage,
158 (void *)this,
159 "HW: begin");
160 p->setHandler(DXPacketIF::INFORMATION,
161 DXExecCtl::HWEndMessage,
162 (void *)this,
163 "HW: end");
164
165 p->setHandler(DXPacketIF::INFORMATION,
166 DXExecCtl::BGBeginMessage,
167 (void *)this,
168 "BG: begin");
169 p->setHandler(DXPacketIF::INFORMATION,
170 DXExecCtl::BGEndMessage,
171 (void *)this,
172 "BG: end");
173
174 SequencerNode* sequencer = theDXApplication->network->sequencer;
175 if (sequencer)
176 sequencer->transmitted = FALSE;
177
178 if (this->inExecOnChange())
179 {
180 this->updateMacros(TRUE);
181 this->resumeExecOnChange();
182 }
183 this->execOnChange = FALSE; // Avoid a resumeExecOnChange()
184 this->endLastExecution(FALSE);
185
186 this->forceNetworkResend = TRUE;
187 this->forceParameterResend = TRUE;
188 this->execOnChangeSuspensions = 0;
189 this->isCurrentlyExecuting = FALSE;
190 this->vcrIsExecuting = FALSE;
191
192 }
193
updateMacros(boolean force)194 void DXExecCtl::updateMacros(boolean force)
195 {
196 DXPacketIF *p = theDXApplication->getPacketIF();
197 if (p == NULL)
198 return;
199 boolean forcenet = force || this->forceNetworkResend;
200 boolean forceparam = force || this->forceParameterResend;
201
202 boolean resume = FALSE;
203
204 if (this->inExecOnChange() AND !this->isExecOnChangeSuspended())
205 {
206 this->suspendExecOnChange();
207 resume = TRUE;
208 }
209
210 this->forceNetworkResend = FALSE;
211 this->forceParameterResend = FALSE;
212
213 #if WORKSPACE_PAGES
214 ProcessGroupManager *pmgr = (ProcessGroupManager*)
215 theDXApplication->network->getGroupManagers()->findDefinition (PROCESS_GROUP);
216 if(pmgr AND pmgr->isDirty())
217 pmgr->sendAssignment(ProcessGroupManager::ATTACH);
218 #else
219 if(theDXApplication->PGManager AND theDXApplication->PGManager->isDirty())
220 theDXApplication->PGManager->
221 sendAssignment(ProcessGroupManager::ATTACH);
222 #endif
223
224 ListIterator ii(theDXApplication->macroList);
225 Network *n;
226 while((n = (Network*)ii.getNext()) != NULL)
227 {
228 boolean dirty = n->isDirty();
229 if (forcenet || dirty)
230 n->sendNetwork();
231 if (forceparam || dirty)
232 n->sendValues(forceparam);
233 }
234
235 n = theDXApplication->network;
236 boolean dirty = n->isDirty();
237 if (forcenet || dirty)
238 n->sendNetwork();
239 if (forceparam || dirty)
240 n->sendValues(forceparam);
241
242 SequencerNode* sequencer = n->sequencer;
243 if (sequencer && (force || NOT sequencer->transmitted))
244 this->vcrTransmit();
245
246 if (resume)
247 this->resumeExecOnChange();
248
249 }
250
vcrFrameSet(char * command)251 void DXExecCtl::vcrFrameSet(char* command)
252 {
253 DXPacketIF *p = theDXApplication->getPacketIF();
254 void (*callback)(void*,int,void*) = NULL;
255
256 if (p != NULL)
257 {
258 if(this->inExecOnChange())
259 {
260 this->suspendExecOnChange();
261 callback = ResumeExecOnChange;
262 }
263
264 p->send(DXPacketIF::FOREGROUND, command, callback);
265 }
266 }
267
vcrTransmit()268 void DXExecCtl::vcrTransmit()
269 {
270 char command[1024];
271 DXPacketIF *p = theDXApplication->getPacketIF();
272 SequencerNode* vcr = theDXApplication->network->sequencer;
273
274 if (p == NULL)
275 return;
276
277 sprintf(command, "sequence %s();\n",
278 theDXApplication->network->getNameString());
279 p->send(DXPacketIF::FOREGROUND, command);
280
281 char *s = vcr->getFrameControlString();
282 p->send(DXPacketIF::FOREGROUND, s);
283 delete s;
284
285 p->send(DXPacketIF::FOREGROUND,
286 vcr->isLoopMode() ? "loop on;\n" : "loop off;\n");
287
288 p->send(DXPacketIF::FOREGROUND,
289 vcr->isPalindromeMode() ? "palindrome on;\n" : "palindrome off;\n");
290
291 vcr->transmitted = TRUE;
292
293 }
294
vcrExecute(int action)295 void DXExecCtl::vcrExecute(int action)
296 {
297 SequencerNode* sequencer = theDXApplication->network->sequencer;
298 DXPacketIF *p = theDXApplication->getPacketIF();
299
300 if (NOT p OR this->vcrIsExecuting OR this->isCurrentlyExecuting )
301 {
302 SequencerDirection direction;
303
304 if(NOT p)
305 ErrorMessage("No Connection to the server.");
306 else
307 ErrorMessage("The program is currently executing.");
308
309 if (action == VCR_FORWARD)
310 direction = (p AND this->vcrIsExecuting ?
311 SequencerNode::BackwardDirection :
312 SequencerNode::Directionless);
313 else
314 direction = (p AND this->vcrIsExecuting ?
315 SequencerNode::ForwardDirection :
316 SequencerNode::Directionless);
317
318 sequencer->setPlayDirection(direction);
319
320 return;
321 }
322
323 this->vcrIsExecuting = TRUE;
324 this->beginSingleExecution(TRUE); // May suspend ExecOnChange.
325
326 p->send(DXPacketIF::FOREGROUND,
327 action==VCR_FORWARD ? "forward;\n" : "backward;\n");
328
329 p->send(DXPacketIF::FOREGROUND, sequencer->isStepMode() ?
330 "step;\n" : "play;\n");
331
332 }
333
vcrCommand(int action,boolean pressed)334 void DXExecCtl::vcrCommand(int action, boolean pressed)
335 {
336 char command[30];
337 DXPacketIF *p = theDXApplication->getPacketIF();
338 SequencerNode* sequencer = theDXApplication->network->sequencer;
339 Widget vcr = NULL;
340 boolean doEnd = FALSE;
341
342 if (action == VCR_STOP) {
343 ASSERT(sequencer);
344 vcr = sequencer->getVCRWidget();
345 }
346
347 if (p == NULL)
348 {
349 // this->endLastExecution(!this->vcrIsExecuting);
350 this->vcrIsExecuting = FALSE;
351 sequencer->setPlayDirection(SequencerNode::Directionless);
352
353 if (action == VCR_STOP)
354 XtVaSetValues(vcr, XmNnext, sequencer->next, NULL);
355
356 return;
357 }
358
359 switch(action)
360 {
361 case VCR_PALINDROME:
362 sequencer->setPalindromeMode(pressed);
363 strcpy(command, pressed ? "palindrome on;\n" : "palindrome off;\n");
364
365 break;
366
367 case VCR_STEP:
368 sequencer->setStepMode(pressed);
369 sequencer->setPlayDirection(SequencerNode::Directionless);
370 strcpy(command, "pause;\n");
371 doEnd = this->vcrIsExecuting;
372 this->vcrIsExecuting = FALSE;
373
374 break;
375
376 case VCR_LOOP:
377 sequencer->setLoopMode(pressed);
378 strcpy(command, pressed ? "loop on;\n" : "loop off;\n");
379
380 break;
381
382 case VCR_PAUSE:
383
384 strcpy(command, "pause;\n");
385 doEnd = this->vcrIsExecuting;
386 this->vcrIsExecuting = FALSE;
387 sequencer->setPlayDirection(SequencerNode::Directionless);
388 break;
389
390 case VCR_STOP:
391
392 strcpy(command, "stop;\n");
393 doEnd = this->vcrIsExecuting;
394 this->vcrIsExecuting = FALSE;
395 sequencer->setPlayDirection(SequencerNode::Directionless);
396
397 break;
398
399 default:
400
401 ASSERT(FALSE);
402 }
403
404 p->send(DXPacketIF::FOREGROUND,command);
405
406 if (action == VCR_STOP)
407 {
408 sequencer->next = sequencer->getStartValue();
409 sprintf(command, "@nextframe = %d;\n", sequencer->next);
410 if(this->inExecOnChange()
411 AND !this->isExecOnChangeSuspended())
412 this->suspendExecOnChange();
413 p->send(DXPacketIF::FOREGROUND, command, ResetVcrNextFrame);
414 }
415
416 if (doEnd)
417 this->endLastExecution(action != VCR_STOP);
418 }
419
ResetVcrNextFrame(void * clientData,int id,void * p)420 void DXExecCtl::ResetVcrNextFrame(void *clientData, int id, void *p)
421 {
422 DXExecCtl *ctl = theDXApplication->getExecCtl();
423 SequencerNode* sequencer = theDXApplication->network->sequencer;
424 ASSERT(sequencer);
425 Widget vcr = sequencer->getVCRWidget();
426
427 sequencer->next = sequencer->getStartValue();
428 XtVaSetValues(vcr, XmNnext, sequencer->next, NULL);
429
430 if(ctl->isExecOnChangeSuspended())
431 ctl->resumeExecOnChange();
432 }
433
enableExecOnChange()434 void DXExecCtl::enableExecOnChange()
435 {
436 DXPacketIF *p = theDXApplication->getPacketIF();
437 if (!p || this->execOnChange)
438 return;
439
440 //
441 // Set the light green now, so that sending big networks looks like
442 // execution.
443 //
444 theDXApplication->notifyClients(DXApplication::MsgExecute);
445
446 //
447 // Update macros here and not in beginSingleExecution() so that
448 // execOnChange doesn't get suspended.
449 //
450 this->updateMacros();
451 this->execOnChange = TRUE;
452
453 //
454 // Go into exec on change mode.
455 //
456 this->resumeExecOnChange();
457
458 //
459 // Do what is usually necessary at the beginning of an execution.
460 //
461 this->beginSingleExecution(FALSE); // updateMacros done above
462
463 //
464 // Now cause the first execution.
465 //
466 char s[100];
467 strcpy(s, theDXApplication->network->getNameString());
468 strcat(s, "();\n");
469 p->send(DXPacketIF::FOREGROUND, s, DXExecCtl::ExecComplete, NULL);
470 }
471 //
472 // Go out of execution on change mode without terminating the current
473 // graph execution. If not current executing, then we go ahead and
474 // go out of eoc mode, otherwise schedule the exit from eoc mode for
475 // the end of the current graph execution (see endLastExecution()).
476 // We return TRUE if we were able to go out of eoc mode now, FALSE if
477 // we won't be going out until the end of the current execution.
478 //
endExecOnChange()479 boolean DXExecCtl::endExecOnChange()
480 {
481 if (!this->inExecOnChange())
482 return TRUE;
483
484 //
485 // If the exec is currently executing, then we will wait to go out
486 // of execute-on-change mode until the current execution completes.
487 // If we don't do this, then the INTERRUPT message to go out of
488 // execute on change, will also kill the current graph execution,
489 // which we don't want to do.
490 //
491 if (this->isCurrentlyExecuting) {
492 this->endExecOnChangePending = TRUE;
493 return FALSE;
494 }
495
496 if (this->vcrIsExecuting) {
497 this->vcrIsExecuting = FALSE; // Only do one endLastExecution().
498 this->vcrCommand(VCR_PAUSE, 0);
499 }
500
501 this->endExecOnChangePending = FALSE;
502 this->execOnChangeSuspensions = 0;
503 this->execOnChange = FALSE;
504 DXPacketIF *p = theDXApplication->getPacketIF();
505 if (p)
506 p->send(DXPacketIF::INTERRUPT);
507
508 theDXApplication->notifyClients(DXApplication::MsgExecuteDone);
509
510 return TRUE;
511
512 }
suspendExecOnChange()513 void DXExecCtl::suspendExecOnChange()
514 {
515 if (!this->inExecOnChange())
516 return;
517
518 if (this->execOnChangeSuspensions == 1)
519 return; // Already suspended
520
521 this->execOnChangeSuspensions = 1;
522
523 DXPacketIF *p = theDXApplication->getPacketIF();
524 if (p) {
525 p->send(DXPacketIF::INTERRUPT);
526 p->sendImmediate("sync");
527 }
528 }
resumeExecOnChange()529 void DXExecCtl::resumeExecOnChange()
530 {
531
532 this->execOnChangeSuspensions = 0;
533 #if 00
534 if (!this->inExecOnChange() || this->isExecuting())
535 return;
536 DXPacketIF *p = theDXApplication->getPacketIF();
537 if (p == NULL)
538 return;
539 #else
540 DXPacketIF *p = theDXApplication->getPacketIF();
541 if (p == NULL)
542 return;
543
544 if (!this->inExecOnChange())
545 return;
546 if (this->isExecuting()) {
547 this->resumeExecOnChangeAfterExecution = TRUE;
548 this->execOnChangeSuspensions = 1;
549 return;
550 }
551 #endif
552
553
554 //
555 // Be sure that all pending assignments/definitions are processed by
556 // the executive before going into execute on change. If we don't do
557 // this we can get multiple executions from the pending assigments.
558 // Note that this an unneeded '$sync' is sent when we are in execute-
559 // on-change and the user does an 'execute-once' command. In this
560 // case we still send the '$sync', but it is not necessary.
561 //
562 p->sendImmediate("sync");
563
564 char s[100];
565 strcpy(s, theDXApplication->network->getNameString());
566 strcat(s, "();\n");
567 p->send(DXPacketIF::BACKGROUND, s);
568 theDXApplication->notifyClients(DXApplication::MsgStandBy);
569 }
executeOnce()570 void DXExecCtl::executeOnce()
571 {
572 DXPacketIF *p = theDXApplication->getPacketIF();
573 if (p == NULL)
574 return;
575
576 #if 0
577 if (this->inExecOnChange())
578 this->suspendExecOnChange();
579 #endif
580
581 this->beginSingleExecution(TRUE);
582
583 char s[100];
584 strcpy(s, theDXApplication->network->getNameString());
585 strcat(s, "();\n");
586 p->send(DXPacketIF::FOREGROUND, s, DXExecCtl::ExecComplete, NULL);
587
588 }
terminateExecution()589 void DXExecCtl::terminateExecution()
590 {
591 #ifdef SET_HW_BUSY_CURSOR
592 if (this->hwExecuting > 0 AND NOT this->hwBusy) {
593 theDXApplication->setBusyCursor(TRUE);
594 this->hwBusy = TRUE;
595 }
596 #endif
597
598 if (!this->isCurrentlyExecuting && !this->execOnChange)
599 return;
600
601 if (this->vcrIsExecuting) {
602 this->vcrIsExecuting = FALSE; // Only do one endLastExecution().
603 this->vcrCommand(VCR_PAUSE, 0);
604 }
605
606 Symbol msg;
607 DXPacketIF *p = theDXApplication->getPacketIF();
608 if (p == NULL) {
609 msg = DXApplication::MsgExecuteDone;
610 //
611 // Set activation of execution dependent commands.
612 //
613 theDXApplication->notExecutingCmd->execute();
614 } else {
615 msg = 0;
616 p->send(DXPacketIF::INTERRUPT);
617 p->send(DXPacketIF::FOREGROUND, "Executive(\"nop\");",
618 DXExecCtl::ExecComplete, NULL);
619 p->sendImmediate("sync");
620 theDXApplication->executeOnChangeCmd->activate();
621 }
622
623 this->execOnChange = FALSE;
624 // FIXME: should use the following but won't right before release...
625 this->isCurrentlyExecuting = FALSE;
626 if (msg)
627 theDXApplication->notifyClients(msg);
628 }
629
updateMacro(Network * n)630 void DXExecCtl::updateMacro(Network *n)
631 {
632 DXPacketIF *p = theDXApplication->getPacketIF();
633 if (p == NULL)
634 return;
635
636 boolean resume = FALSE;
637
638 if (n->isDirty())
639 {
640 if (this->inExecOnChange() AND !this->isExecOnChangeSuspended())
641 {
642 this->suspendExecOnChange();
643 resume = TRUE;
644 }
645
646 n->sendNetwork();
647 n->sendValues();
648
649 if (resume)
650 this->resumeExecOnChange();
651 }
652 }
653
654 //
655 // This function is called with a boolean that, in essence, indicates
656 // whether the system is quiescent (updateable) or active (i.e. as a
657 // result of the BG: begin message, and thus not updateable).
beginSingleExecution(boolean update)658 void DXExecCtl::beginSingleExecution(boolean update)
659 {
660 theDXApplication->notifyClients(DXApplication::MsgExecute);
661
662 if (update && this->inExecOnChange() && !this->isExecOnChangeSuspended())
663 this->suspendExecOnChange();
664
665 theDXApplication->clearErrorList();
666
667 if (update)
668 this->updateMacros();
669
670 this->isCurrentlyExecuting = TRUE;
671 //
672 // Set activation of execution dependent commands.
673 //
674 theDXApplication->executingCmd->execute();
675
676 }
677
endLastExecution(boolean resume)678 void DXExecCtl::endLastExecution(boolean resume)
679 {
680 this->isCurrentlyExecuting = FALSE;
681 SequencerNode* sequencer = theDXApplication->network->sequencer;
682 Symbol msg = 0;
683
684 if (this->vcrIsExecuting)
685 {
686 if (sequencer->isStepMode())
687 this->vcrIsExecuting = FALSE;
688 }
689
690 if ((resume || this->resumeExecOnChangeAfterExecution) AND
691 this->isExecOnChangeSuspended()) {
692 this->resumeExecOnChange(); // This may result in MsgStandBy message
693 } else if (this->inExecOnChange() && !this->isExecOnChangeSuspended()) {
694 if (this->hwExecuting <= 0)
695 msg = DXApplication::MsgStandBy;
696 }
697
698 //
699 // If a request to exit ExecOnChange mode was requested during an
700 // execution, then do it now.
701 //
702 if (this->endExecOnChangePending) {
703 this->endExecOnChangePending = FALSE;
704 this->endExecOnChange();
705 msg = 0;
706 }
707
708 this->resumeExecOnChangeAfterExecution = FALSE;
709
710 //
711 // Set activation of execution dependent commands.
712 //
713 theDXApplication->notExecutingCmd->execute();
714
715 //
716 // Indicate the nodes that had errors.
717 // FIXME: only do this if there are errors.
718 //
719 theDXApplication->refreshErrorIndicators();
720
721 if (msg)
722 theDXApplication->notifyClients(msg);
723 }
724