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
11
12 #define tdmRender_c
13
14
15 #include <stdio.h>
16
17 #if defined(HAVE_SIGNAL_H)
18 #include <signal.h>
19 #endif
20
21 #if defined(HAVE_STRING_H)
22 #include <string.h>
23 #endif
24
25 #include <stdlib.h>
26
27 #if defined(HAVE_SYS_WAIT_H)
28 #include <sys/wait.h>
29 #endif
30
31 #if defined(HAVE_SYS_PARAM_H)
32 #include <sys/param.h>
33 #endif
34
35 #if defined(HAVE_NETDB_H)
36 #include <netdb.h>
37 #endif
38
39 #if defined(HAVE_NETINET_IN_H)
40 #include <netinet/in.h>
41 #endif
42
43 #if defined(HAVE_ARPA_INET_H)
44 #include <arpa/inet.h>
45 #endif
46
47 #if defined(HAVE_UNISTD_H)
48 #include <unistd.h>
49 #endif
50
51 #if defined(DX_NATIVE_WINDOWS)
52 #include <windows.h>
53 #include <gl/gl.h>
54 #include <gl/glu.h>
55 #include <gl/glaux.h>
56 #endif
57
58 #include "hwDeclarations.h"
59 #include "hwWindow.h"
60 #include "hwMemory.h"
61 #include "hwSort.h"
62
63 #include "hwDebug.h"
64
65 /*
66 #if defined(sgi)
67 int TryDGL(char *, int);
68 #endif
69 */
70
71 #define CACHEPREFIX "tdmRender/"
72 #define CACHEKEY 0x1234ABCD
73
74 typedef Error (*Handler)(int, Pointer) ;
75 static char* _getFullHostName(char* givenName);
76 extern Error _dxfDrawMonoInCurrentContext (void*, dxObject, Camera, int buttonUp);
77
78 #if defined(DX_NATIVE_WINDOWS)
79
_dxfRenderImage(tdmChildGlobalP globals,int flag)80 Error _dxfRenderImage(tdmChildGlobalP globals, int flag)
81 {
82 DEFGLOBALDATA(globals);
83
84 //PostMessage(XWINID, WM_PAINT, 0, 0);
85 _dxfDraw(globals, OBJECT, CAMERA, 1);
86 return OK;
87 }
88 tdmPortHandleP_dxfNewPortHandle(tdmParsedFormatP format);
89
90 #else /* !(DX_NATIVE_WINDOWS) */
91
92 static Display* hwDpy = NULL;
93
94 static char* _getFullXserver(char* givenXserver);
95 int _dxfCatchWinopenErrors (Display *dpy, XErrorEvent *error) ;
96 Error _dxfProcessEvents (int fd, tdmChildGlobalP globals, int flag);
97
_dxfProcessEventsInputHandler(int fd,tdmChildGlobalP globals)98 Error _dxfProcessEventsInputHandler(int fd, tdmChildGlobalP globals)
99 {
100 return _dxfProcessEvents(fd, globals, 0);
101 }
102
103 #if 0
104 Error _dxfRenderImage(tdmChildGlobalP globals, int flag)
105 {
106 return _dxfProcessEvents(-1, globals, flag);
107 }
108 Error _dxfRenderImageInputHandler(int fd, tdmChildGlobalP globals)
109 {
110 return _dxfRenderImage(globals, 0);
111 }
112 #endif
113
114 static int
WindowChecker(int fd,void * d)115 WindowChecker(int fd, void *d)
116 {
117 tdmChildGlobalP globals = (tdmChildGlobalP)d;
118 DEFGLOBALDATA(globals) ;
119 return XPending(DPY);
120 }
121 tdmPortHandleP _dxfNewPortHandle(tdmParsedFormatP format, Display **dpy);
122
123 #endif
124
125 tdmParsedFormatT*
126 _tdmParseDisplayString (char *displayString,char** cacheIdP);
127
128 static Error
129 _validateDisplayString(tdmParsedFormatT *pFormat, int Pass);
130
131 Error
132 _dxfDeleteParsedDisplayString(tdmParsedFormatT *pFormat);
133
134 static Error
135 _dxfDeleteCachedDisplayString(Pointer arg);
136
137 static tdmParsedFormatT*
138 _dxfCopyParsedDisplayString(tdmParsedFormatT *pFormat);
139
140 extern void
141 _dxfSetInteractionMode(tdmChildGlobalP globals, int mode, dxObject args);
142
143 int isOpenGL = 0;
144
CanDoOGL(char * Where)145 int CanDoOGL(char * Where) /* Are GLX Extensions Available on Where ? */
146 {
147 #if defined(DX_NATIVE_WINDOWS)
148 return 1;
149 #else
150
151 static int FirstPass = 1;
152 static int RetVal;
153 Display *Dpy;
154
155 if(FirstPass)
156 {
157 if(getenv("DXHWMOD")) {
158 if(0 == strcmp("DXhwdd.o", getenv("DXHWMOD")))
159 return RetVal = 0;
160 else
161 return RetVal = 1;
162 } else
163 RetVal = 1;
164 FirstPass = 0;
165 }
166 if(RetVal == 0)
167 return 0;
168
169 if((Dpy = XOpenDisplay(Where)))
170 {
171 int Extra, Major, Valid;
172
173 Valid = XQueryExtension(Dpy, "GLX", &Major, &Extra, &Extra);
174 XCloseDisplay(Dpy);
175 if(Valid && (Major > 0))
176 return 1;
177 else
178 return 0;
179 }
180 return 0;
181 #endif
182 }
183
184 Error
_dxfRedrawInActiveContext(dxObject r,Camera c,char * displayString)185 _dxfRedrawInActiveContext (dxObject r, Camera c, char *displayString)
186 {
187 Private cacheObject = NULL;
188 char* cacheId = NULL;
189
190 /* Need to build up the globals then call _dxfDraw() */
191 tdmChildGlobalP globals = NULL;
192 tdmParsedFormatT *pFormat = NULL;
193
194 if (!c && !DXGetImageBounds(r,NULL,NULL,NULL,NULL))
195 goto error;
196
197
198 /* get host and window name from display string, fill in the cache id */
199 if (!(pFormat = _tdmParseDisplayString (displayString, &cacheId)))
200 goto error;
201
202 /* validate the display string */
203 if (!(_validateDisplayString(pFormat, 1)))
204 goto error ;
205
206 /* Get a pointer to the global data, out of the cache or create a new one. */
207 if((cacheObject = (Private) DXGetCacheEntry(cacheId, 0, 0)) != NULL) {
208 globals = (tdmChildGlobalP) DXGetPrivateData(cacheObject) ;
209
210 /* Create a reference so this doesn't get deleted while I'm using it */
211 DXReference ((Pointer)cacheObject);
212
213 /* associate cacheId with cacheObject, set to permanent status */
214 if(! DXSetCacheEntry((Pointer)cacheObject, CACHE_PERMANENT,
215 cacheId, 0, 0)) {
216 /* Can't set cache entry for tdm globals */
217 DXErrorGoto (ERROR_INTERNAL, "#13300") ;
218 }
219
220 /* save the cacheId to allow cache deletion upon DestroyNotify event */
221 if(! (globals->cacheId = tdmAllocate(strlen(cacheId)+1))) {
222 DXErrorGoto (ERROR_NO_MEMORY, "") ;
223 }
224
225 /* save cacheId */
226 strcpy(globals->cacheId,cacheId) ;
227 } else {
228 DXErrorGoto(ERROR_INTERNAL, "object must be previously rendered");
229 }
230
231 /* Now that we have a global store, use it */
232 {
233 int needInit = 0;
234 DEFGLOBALDATA(globals);
235
236 if (!OBJECT || (OBJECT && OBJECT_TAG != DXGetObjectTag(r)))
237 {
238 if (OBJECT)
239 DXDelete(OBJECT);
240
241 OBJECT = DXReference(r);
242 OBJECT_TAG = DXGetObjectTag(r);
243 needInit = 1;
244 }
245
246 if (!CAMERA || (CAMERA && CAMERA_TAG != DXGetObjectTag((dxObject)c)))
247 {
248 if (CAMERA)
249 DXDelete(CAMERA);
250
251 CAMERA = DXReference((dxObject)c);
252 CAMERA_TAG = DXGetObjectTag((dxObject)c);
253 needInit = 1;
254 }
255
256 if(CAMERA && needInit)
257 {
258 if(!_dxfInitRenderObject(LWIN)) {
259 /* unable to set up for rendering */
260 DXErrorGoto(ERROR_NO_HARDWARE_RENDERING, "#13350");
261 }
262 }
263 }
264
265 {
266 DEFWINDATA(&(globals->win));
267 _dxfDrawMonoInCurrentContext(globals, OBJECT, CAMERA, 1);
268 }
269
270 if(cacheObject) {
271 /* delete the working reference */
272 DXDelete((Pointer)cacheObject) ;
273 cacheObject = NULL;
274 }
275
276 if (cacheId)
277 tdmFree(cacheId);
278 if (pFormat)
279 _dxfDeleteParsedDisplayString(pFormat);
280
281
282 return OK;
283
284 error:
285
286 if(cacheObject) {
287 /* delete the working reference */
288 DXDelete((Pointer)cacheObject) ;
289 cacheObject = NULL;
290 }
291
292 if (cacheId)
293 tdmFree(cacheId);
294 if (pFormat)
295 _dxfDeleteParsedDisplayString(pFormat);
296
297 EXIT(("ERROR"));
298 DEBUG_MARKER("_dxfAsyncRender EXIT");
299 return ERROR ;
300 }
301
302 Error
_dxfAsyncRender(dxObject r,Camera c,char * obsolete,char * displayString)303 _dxfAsyncRender (dxObject r, Camera c, char *obsolete, char *displayString)
304 {
305 Private cacheObject = NULL;
306 tdmChildGlobalP globals = NULL;
307 char* cacheId = NULL;
308 tdmParsedFormatT *pFormat = NULL;
309 dxObject attr;
310
311
312 ENABLE_DEBUG();
313 DEBUG_MARKER("_dxfAsyncRender ENTRY");
314 ENTRY(("_dxfAsyncRender (0x%x, 0x%x, \"%s\", \"%s\")",
315 r, c, obsolete, displayString));
316
317 # if defined(DEBUG)
318
319 if(DXGetAttribute(r, "force env var")) {
320 char *Buff;
321
322 if(DXExtractString(DXGetAttribute(r, "force env var"), &Buff)) {
323 PRINT(("Putting Variable %s\n", Buff));
324 putenv(Buff);
325 }
326 }
327 # endif
328
329
330 if (!c && !DXGetImageBounds(r,NULL,NULL,NULL,NULL))
331 goto error;
332
333
334 /* get host and window name from display string, fill in the cache id */
335 if (!(pFormat = _tdmParseDisplayString (displayString, &cacheId)))
336 goto error;
337
338 /* validate the display string */
339 if (!(_validateDisplayString(pFormat, 1)))
340 goto error ;
341
342 /* Get a pointer to the global data, out of the cache or create a new one. */
343 if((cacheObject = (Private) DXGetCacheEntry(cacheId, 0, 0)) != NULL) {
344 globals = (tdmChildGlobalP) DXGetPrivateData(cacheObject) ;
345 #if defined(DX_NATIVE_WINDOWS)
346 /*
347 * Now lock globals so that rendering doesn't occur in another
348 * thread until the setup is done. If we create a globals structure
349 * here, the lock is created in CreateRenderModule, and its created
350 * owned.
351 */
352 {
353 DEFGLOBALDATA(globals);
354 if (DXWaitForSignal(1, &LOCK) == WAIT_TIMEOUT)
355 goto error;
356 }
357 #endif
358
359 } else {
360 if(!(globals = (tdmChildGlobalP)_dxfCreateRenderModule(pFormat)))
361 return ERROR;
362
363 /* save globals in cache; call _dxfEndRenderModule when cache deleted */
364 if(!(cacheObject = (Private)
365 DXNewPrivate((Pointer) globals,
366 (Error (*)(Pointer))_dxfEndRenderModule))) {
367 /* Can't cache tdm globals */
368 DXErrorGoto (ERROR_INTERNAL, "#13290");
369 }
370
371 /* Create a reference so this doesn't get deleted while I'm using it */
372 DXReference ((Pointer)cacheObject);
373
374 /* associate cacheId with cacheObject, set to permanent status */
375 if(! DXSetCacheEntry((Pointer)cacheObject, CACHE_PERMANENT,
376 cacheId, 0, 0)) {
377 /* Can't set cache entry for tdm globals */
378 DXErrorGoto (ERROR_INTERNAL, "#13300") ;
379 }
380
381 /* save the cacheId to allow cache deletion upon DestroyNotify event */
382 if(! (globals->cacheId = tdmAllocate(strlen(cacheId)+1))) {
383 DXErrorGoto (ERROR_NO_MEMORY, "") ;
384 }
385
386 /* save cacheId */
387 strcpy(globals->cacheId,cacheId) ;
388 }
389
390 /* Now that we have a global store, use it */
391 {
392 int needInit = 0;
393 DEFGLOBALDATA(globals);
394
395 if (!OBJECT || (OBJECT && OBJECT_TAG != DXGetObjectTag(r)))
396 {
397 if (OBJECT)
398 DXDelete(OBJECT);
399
400 OBJECT = DXReference(r);
401 OBJECT_TAG = DXGetObjectTag(r);
402 needInit = 1;
403 }
404
405 if (!CAMERA || (CAMERA && CAMERA_TAG != DXGetObjectTag((dxObject)c)))
406 {
407 if (CAMERA)
408 DXDelete(CAMERA);
409
410 CAMERA = DXReference((dxObject)c);
411 CAMERA_TAG = DXGetObjectTag((dxObject)c);
412 needInit = 1;
413 }
414
415 _dxfInitializeStereoSystemMode(globals, DXGetAttribute(r, "stereo system mode"));
416 _dxfInitializeStereoCameraMode(globals, DXGetAttribute(r, "stereo camera mode"));
417
418 if(CAMERA && needInit)
419 {
420 if(!_dxfInitRenderObject(LWIN)) {
421 /* unable to set up for rendering */
422 DXErrorGoto(ERROR_NO_HARDWARE_RENDERING, "#13350");
423 }
424 }
425
426 /* Handle X events and redraw the image */
427 #if !defined(DX_NATIVE_WINDOWS)
428 if(! _dxfProcessEvents (-1, globals, 1))
429 goto error;
430 #endif
431
432 }
433
434 if ((attr = DXGetAttribute((dxObject)c, "camera interaction mode")) == NULL)
435 if ((attr = DXGetAttribute(r, "object interaction mode")) == NULL)
436 attr = DXGetAttribute(r, "interaction mode");
437
438 if (attr) {
439 Array amode;
440 int mode;
441
442 if (DXGetObjectClass(attr) == CLASS_GROUP) {
443 if (NULL == (amode = (Array)DXGetMember((Group)attr, "mode")))
444 DXErrorGoto(ERROR_DATA_INVALID,
445 "interaction mode args group must contain a member named \"mode\"");
446 } else if (DXGetObjectClass(attr) != CLASS_ARRAY) {
447 DXErrorGoto(ERROR_DATA_INVALID,
448 "interaction mode args must be a group or array");
449 } else
450 amode = (Array)attr;
451
452 if (DXExtractInteger((dxObject)amode, &mode))
453 _dxfSetInteractionMode(globals, mode, attr);
454 else
455 DXErrorGoto(ERROR_DATA_INVALID,
456 "interaction mode attribute must be an integer");
457 } else
458 _dxfSetInteractionMode(globals, 11, NULL);
459
460 if(cacheObject) {
461 /* delete the working reference */
462 DXDelete((Pointer)cacheObject) ;
463 cacheObject = NULL;
464 }
465
466 if (cacheId)
467 tdmFree(cacheId);
468 if (pFormat)
469 _dxfDeleteParsedDisplayString(pFormat);
470
471 EXIT(("OK"));
472 DEBUG_MARKER("_dxfAsyncRender EXIT");
473 return OK ;
474
475 error:
476
477 if(cacheObject) {
478 /* delete the working reference */
479 DXDelete((Pointer)cacheObject) ;
480 cacheObject = NULL;
481 }
482
483 if (cacheId)
484 tdmFree(cacheId);
485 if (pFormat)
486 _dxfDeleteParsedDisplayString(pFormat);
487
488 EXIT(("ERROR"));
489 DEBUG_MARKER("_dxfAsyncRender EXIT");
490 return ERROR ;
491 }
492
493 extern Field _dxfCaptureHardwareImage(tdmChildGlobalP);
494
495 dxObject
_dxfSaveHardwareWindow(char * where)496 _dxfSaveHardwareWindow(char *where)
497 {
498 Private cacheObject = NULL;
499 tdmChildGlobalP globals = NULL;
500 char* cacheId = NULL;
501 tdmParsedFormatT* pFormat = NULL;
502 Field image = NULL;
503
504 /*
505 * get host and window name from display string, fill in the cache id
506 */
507 if (!(pFormat = _tdmParseDisplayString (where, &cacheId)))
508 goto error;
509
510 /*
511 * validate the display string
512 */
513 if (!(_validateDisplayString(pFormat, 1)))
514 goto error ;
515
516 /*
517 * Get a pointer to the global data
518 */
519 cacheObject = (Private) DXGetCacheEntry(cacheId, 0, 0);
520 if (! cacheObject) {
521 DXSetError(ERROR_BAD_PARAMETER,
522 "window matching \"%s\" not found", where);
523 goto error;
524 } else {
525 globals = (tdmChildGlobalP) DXGetPrivateData(cacheObject) ;
526 image = _dxfCaptureHardwareImage(globals);
527 if (! image)
528 goto error;
529 }
530
531
532 error:
533 if (pFormat)
534 _dxfDeleteParsedDisplayString(pFormat);
535
536 if (cacheId)
537 tdmFree(cacheId);
538
539 /*
540 * delete the working reference
541 */
542 if(cacheObject)
543 DXDelete((Pointer)cacheObject) ;
544
545 return (dxObject)image;
546 }
547
548 int BackingStore = TRUE;
549
550
551 void
_dxfDestroyRenderModule(tdmChildGlobalP globals)552 _dxfDestroyRenderModule(tdmChildGlobalP globals)
553 {
554 DEFGLOBALDATA(globals) ;
555 if (STEREOCAMERAMODE >= 0)
556 _dxfExitStereoCameraMode(globals);
557 if (STEREOSYSTEMMODE >= 0)
558 _dxfExitStereoSystemMode(globals);
559 DXDelete(OBJECT);
560 tdmFree(WHERE);
561 _dxf_deleteSortList(SORTLIST);
562 tdmFree(globals);
563 }
564
565 #if !defined(DX_NATIVE_WINDOWS)
566 static int
XChecker(int fd,void * d)567 XChecker(int fd, void *d)
568 {
569 tdmChildGlobalP globals = (tdmChildGlobalP)d;
570 DEFGLOBALDATA(globals) ;
571 return XPending(DPY);
572 }
573 #endif
574
575 #if !defined(DX_NATIVE_WINDOWS)
576 extern Error DXRegisterWindowHandlerWithCheckProc(Error (*proc) (int, Pointer),
577 int (*check)(int, Pointer), Display *d, Pointer arg);
578 #endif
579
_dxfCreateRenderModule(tdmParsedFormatT * format)580 tdmChildGlobalP _dxfCreateRenderModule(tdmParsedFormatT *format)
581 {
582 tdmChildGlobalP globals = NULL ;
583 tdmPortHandleP portHandle;
584
585 ENTRY(("_dxfCreateRenderModule (0x%x)",format));
586
587 #if 0
588 /* If different 'where' open new connections (NULL to newPortHandle) */
589 if(!strlen(hwWhere) || strcmp(format->where,hwWhere))
590 #endif
591
592 #if !defined(DX_NATIVE_WINDOWS)
593
594 hwDpy = NULL;
595
596 if(!(portHandle = _dxfNewPortHandle(format,&hwDpy)))
597 #else
598
599 if(!(portHandle = _dxfNewPortHandle(format)))
600 #endif
601
602 {
603 EXIT(("_dxfNewPortHandle failed"));
604 return NULL;
605 }
606 /* Got the HW Layer, ReCheck the DisplayString */
607
608 if (!(_validateDisplayString(format, 2)))
609 goto error;
610
611 /* allocate globals */
612 if (! (globals = (tdmChildGlobalP)
613 tdmAllocateZero (sizeof(tdmChildGlobalT))))
614 /* can't allocate render globals */
615 DXErrorGoto (ERROR_NO_MEMORY, "#13270") ;
616
617 {
618 DEFGLOBALDATA(globals) ;
619 DEFPORT(portHandle);
620
621 #if !defined(DX_NATIVE_WINDOWS)
622
623 DPY = hwDpy;
624 #endif
625
626 PORT_HANDLE = portHandle;
627
628 STEREOCAMERAMODE = -1;
629 STEREOSYSTEMMODE = -1;
630
631 SORTLIST = _dxf_newSortList();
632
633 #if defined(DX_NATIVE_WINDOWS)
634 /* Then input to the window does not come through the X event loop (there ain't
635 * one, after all). Instead, they are handled in a separate thread thats watching
636 * messages for the window
637 */
638 LOCK = CreateMutex(NULL, TRUE, NULL);
639
640 if (! _dxfCreateHWWindow(globals, format->name, NULL))
641 goto error;
642
643 #else
644 /* _dxfProcessEvents() is the input handler for the X connection fd */
645 DXRegisterWindowHandlerWithCheckProc ((Handler) _dxfProcessEventsInputHandler,
646 XChecker, DPY, (Pointer) globals) ;
647
648 /* create graphics window */
649 if (! _dxfCreateWindow (globals, format->name))
650 goto error ;
651
652 #endif
653
654
655 /* initialize graphics API */
656 if (! _dxf_INIT_RENDER_MODULE (globals))
657 goto error ;
658
659 if (format->where) {
660 WHERE = (char *)DXAllocate(strlen(format->where) + 1);
661 strcpy(WHERE, format->where);
662 } else
663 WHERE = NULL;
664
665 if (format->originalWhere) {
666 ORIGINALWHERE = (char *)DXAllocate(strlen(format->originalWhere) + 1);
667 strcpy(ORIGINALWHERE, format->originalWhere);
668 } else
669 ORIGINALWHERE = NULL;
670
671 LINK = format->link;
672
673 /* Undocumented environment varaible to enable FLING mode for
674 Marketing persons. This varaible is not presented to users. */
675 if(getenv("DXFLING"))
676 _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_FLING);
677
678 if((_dxf_GET_VERSION(NULL) != 0x080001) &&
679 (_dxf_GET_VERSION(NULL) > 0.0))
680 _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_DOES_TRANS);
681
682 if(getenv("DXHW_VERBOSE")) {
683 int dsoVer;
684 char * dsoStr;
685
686 dsoVer = _dxf_GET_VERSION(&dsoStr);
687 DXMessage("%s DSO rev %x.%x.%x", dsoStr,
688 dsoVer >> 16, (dsoVer & 0xff00) >> 8, dsoVer & 0xff);
689 }
690
691 /*
692 * Environment varaible documented only for Freedom 6000.
693 * Will disable frame buffer readbacks on machines that are slow.
694 */
695 if(getenv("DXNO_BACKING_STORE"))
696 _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE);
697
698 if(!BackingStore)
699 _dxf_setFlags(_dxf_SERVICES_FLAGS(), SF_INVALIDATE_BACKSTORE);
700 }
701
702 EXIT(("globals = 0x%x",globals));
703 return globals ;
704
705 error:
706 if (globals)
707 _dxfDestroyRenderModule(globals);
708
709 EXIT(("globals = NULL"));
710 return NULL ;
711 }
712
713
714 #define EQLSTR(str1,str2) (!strcmp(str1,str2))
715
716 static char* _token(char* str, char* delimit, char* chaff, int inPlace);
717
718 #if 0
719 /* This is never called */
720 static int
721 _isSameInstance(tdmParsedFormatT *first,
722 tdmParsedFormatT *second )
723 {
724 ENTRY(("isSaveInstance(0x%x, 0x%x)",first,second));
725
726 if(!EQLSTR(first->type,second->type) ||
727 !EQLSTR(first->fullHost,second->fullHost) ||
728 !EQLSTR(first->Xserver,second->Xserver) ||
729 !EQLSTR(first->name,second->name)) {
730 EXIT(("NO"));
731 return 0;
732 }
733
734 EXIT(("YES"));
735 return 1;
736 }
737 #endif
738
739 /* i've added some new code here. the first time through, a display
740 * string is parsed up and stored in a tdmParsedFormatT struct.
741 * a copy of the parse struct plus a parsed cache id string is put
742 * into a private object and cached with the display string as the key.
743 * the next time through, the info in the private object is retrieved
744 * instead of reparsing. the most offensive part of reparsing is that
745 * it calls gethostname() which can be expensive if your nameserver is
746 * overloaded or down. nsc 08may96
747 */
748
749 /* new. this routine deletes the private data associated with a cached
750 * private object. the format of the private data is given below.
751 */
_dxfDeleteCachedDisplayString(Pointer arg)752 static Error _dxfDeleteCachedDisplayString(Pointer arg)
753 {
754 ubyte **ptr = (ubyte **)arg;
755
756 if (!tdmFree((char *)(ptr[0])))
757 return ERROR;
758 if (!_dxfDeleteParsedDisplayString((tdmParsedFormatT*)(ptr[1])))
759 return ERROR;
760
761 if (!tdmFree(ptr))
762 return ERROR;
763
764 return OK;
765 }
766
767 /* existing. this routine deletes a tdmParsedFormatT struct from memory
768 */
_dxfDeleteParsedDisplayString(tdmParsedFormatT * pFormat)769 Error _dxfDeleteParsedDisplayString(tdmParsedFormatT *pFormat)
770 {
771
772 ENTRY(("_dxfDeleteParsedDisplayString(0x%x)",pFormat));
773
774 if(!pFormat) {
775 EXIT(("ERROR"));
776 return ERROR;
777 }
778
779 if(pFormat->type)
780 tdmFree(pFormat->type);
781
782 if(pFormat->where)
783 tdmFree(pFormat->where);
784
785 if(pFormat->name)
786 tdmFree(pFormat->name);
787
788 if(pFormat->Xserver)
789 tdmFree(pFormat->Xserver);
790
791 if(pFormat->fullHost)
792 tdmFree(pFormat->fullHost);
793
794 if(pFormat->localHost)
795 tdmFree(pFormat->localHost);
796
797 if(pFormat->originalWhere)
798 tdmFree(pFormat->originalWhere);
799
800 /* notice they skip the cacheId. it's never initialized so this is good. */
801
802 tdmFree(pFormat);
803
804 EXIT(("OK"));
805 return OK;
806 }
807
808 /* new. this makes and returns a new copy of the struct and
809 * all the strings in it.
810 */
811 static tdmParsedFormatT*
_dxfCopyParsedDisplayString(tdmParsedFormatT * pFormat)812 _dxfCopyParsedDisplayString(tdmParsedFormatT *pFormat)
813 {
814 tdmParsedFormatT *newcopy = NULL;
815
816 ENTRY(("_dxfDeleteParsedDisplayString(0x%x)",pFormat));
817
818 if(!pFormat)
819 goto error;
820
821 newcopy = tdmAllocateZero(sizeof(tdmParsedFormatT));
822 if (!newcopy)
823 goto error;
824
825 #define DO_COPY(thing) \
826 if (pFormat->thing) { \
827 newcopy->thing = tdmAllocate(strlen(pFormat->thing) + 1); \
828 if (!newcopy->thing) \
829 goto error; \
830 strcpy(newcopy->thing, pFormat->thing); \
831 }
832
833 DO_COPY(type);
834 DO_COPY(where);
835 DO_COPY(fullHost);
836 DO_COPY(localHost);
837 DO_COPY(Xserver);
838 DO_COPY(name);
839 newcopy->link = pFormat->link;
840 DO_COPY(originalWhere);
841 /* DO_COPY(cacheId); -- this seems never to be used nor initialized */
842
843 EXIT(("OK"));
844 return newcopy;
845
846 error:
847 /* should clean up partially allocated structs here */
848 EXIT(("ERROR"));
849 return NULL;
850 }
851
852 /* i added a private data object to this routine, cached by
853 * the contents of the display string. if not found, the
854 * string is parsed and both the cacheid string and the
855 * parsed tdm structure are saved for next time. the structure
856 * of the private data block is:
857 * addr of cacheIdP char string
858 * addr of tdmParsedFormatT struct
859 * if found in cache, the contents are copied so they can be
860 * deleted in the exit code and not affect the cached versions.
861 */
862 tdmParsedFormatT*
_tdmParseDisplayString(char * displayString,char ** cacheIdP)863 _tdmParseDisplayString (char *displayString, char** cacheIdP)
864 {
865 char *whereHostP = NULL, *XserverP = NULL;
866 tdmParsedFormatT *pFormat;
867 dxObject id;
868 ubyte **priv;
869
870 ENTRY(("_tdmParseDisplayString (\"%s\", 0x%x)",displayString, cacheIdP));
871
872 /* if we've been here before with this display string, get it from cache.
873 */
874 if ((id = DXGetCacheEntry(displayString, CACHEKEY, 0)) != NULL) {
875
876 priv = (ubyte **)DXGetPrivateData((Private)id);
877 if (!priv)
878 goto reparse;
879
880 *cacheIdP = tdmAllocate(strlen((char *)(priv[0])) + 1);
881 if (!(*cacheIdP))
882 goto error;
883
884 strcpy(*cacheIdP, (char *)(priv[0]));
885 pFormat = _dxfCopyParsedDisplayString((tdmParsedFormatT*)(priv[1]));
886
887 /* GetCacheEntry adds a reference. we have a copy now so the extra
888 * reference to the cached copy can be deleted.
889 */
890 DXDelete(id);
891
892 EXIT(("pFormat (found in cache) = 0x%x",pFormat));
893 return pFormat;
894 }
895
896 reparse:
897 /* if new string, or if the old cache info has been flushed, do it again
898 */
899 if(!(pFormat = tdmAllocate(sizeof(tdmParsedFormatT))))
900 goto error;
901
902 pFormat->originalWhere = tdmAllocate(strlen(displayString)+1);
903 strcpy(pFormat->originalWhere, displayString);
904
905 pFormat->type = _token(displayString,","," \t",0);
906 pFormat->where = _token(NULL,","," \t",0);
907 pFormat->name = _token(NULL,","," \t",0);
908
909 if(!pFormat->type || !pFormat->where || !pFormat->name)
910 goto error;
911
912 /* Set defaults for NULL or blank values */
913
914 /* type */
915 if(!*pFormat->type) {
916 tdmFree(pFormat->type);
917 if(!(pFormat->type = _token("X","","",0)))
918 goto error;
919 }
920
921 /* name */
922 if(!*pFormat->name) {
923 tdmFree(pFormat->name);
924 if(!(pFormat->name = _token("Image","","",0)))
925 goto error;
926 }
927
928 /* where */
929 /*
930 * If no 'where' given default comes for "DISPLAY" env variable.
931 * If a 'where' is given, we must set the "DISPLAY" env to it.
932 */
933 if(!*pFormat->where) {
934 char* env_dis;
935
936 tdmFree(pFormat->where);
937 if(!(env_dis = (char*)getenv("DISPLAY"))) {
938 pFormat->where = NULL;
939 } else {
940 if(!(pFormat->where = _token(env_dis,"","",0)))
941 goto error;
942 }
943 }
944
945 pFormat->link = pFormat->name &&
946 strlen(pFormat->name) > 2 &&
947 pFormat->name[0] == '#' &&
948 pFormat->name[1] == 'X';
949
950 #if !defined(DX_NATIVE_WINDOWS)
951
952 /*
953 * Divide up the 'where' parameter and get the full host name and server
954 * designator (ex. :0.0)
955 */
956
957 whereHostP = _token(pFormat->where,":"," \t",0);
958 XserverP = _token(NULL,""," \t",0);
959 pFormat->Xserver = _getFullXserver(XserverP);
960 pFormat->fullHost = _getFullHostName(whereHostP);
961 pFormat->localHost = _getFullHostName("localhost");
962
963 if(! pFormat->Xserver || !whereHostP || !XserverP)
964 goto error;
965
966 if(!pFormat->fullHost || !pFormat->localHost) {
967 /* gethostname failed */
968 DXSetError (ERROR_INTERNAL,"#13690");
969 goto error;
970 }
971
972 if( cacheIdP &&
973 (*cacheIdP = tdmAllocate(strlen(CACHEPREFIX)+
974 strlen(pFormat->type)+
975 strlen(pFormat->fullHost)+
976 strlen(pFormat->Xserver)+
977 strlen(pFormat->name)+
978 1))) {
979 strcpy(*cacheIdP,CACHEPREFIX);
980 strcat(*cacheIdP,pFormat->type);
981 strcat(*cacheIdP,pFormat->fullHost);
982 strcat(*cacheIdP,pFormat->Xserver);
983 strcat(*cacheIdP,pFormat->name);
984 }
985
986 tdmFree(whereHostP);
987 tdmFree(XserverP);
988 #else
989
990 if( cacheIdP &&
991 (*cacheIdP = tdmAllocate(strlen(CACHEPREFIX)+
992 strlen(pFormat->type)+
993 strlen(pFormat->name)+
994 1))) {
995 strcpy(*cacheIdP,CACHEPREFIX);
996 strcat(*cacheIdP,pFormat->type);
997 strcat(*cacheIdP,pFormat->name);
998 }
999
1000
1001 pFormat->Xserver = NULL;
1002 pFormat->fullHost = NULL;
1003 pFormat->localHost = NULL;
1004
1005 #endif
1006 /* cache this info for next time */
1007 priv = (ubyte **)tdmAllocate(sizeof(ubyte *) * 2);
1008 if (!priv)
1009 goto error;
1010
1011 priv[0] = (ubyte *)tdmAllocate(strlen(*cacheIdP) + 1);
1012 if (!priv[0])
1013 goto error;
1014
1015 strcpy((void *)(priv[0]), (void *)*cacheIdP);
1016 priv[1] = (ubyte *)_dxfCopyParsedDisplayString(pFormat);
1017 if (!priv[1])
1018 goto error;
1019
1020 id = (dxObject)DXNewPrivate((Pointer)priv, _dxfDeleteCachedDisplayString);
1021 if (!id)
1022 goto error;
1023
1024 /* put it in the cache using the original display string as the key. */
1025 if (!DXSetCacheEntry(id, 0.0, displayString, CACHEKEY, 0))
1026 goto error;
1027
1028 EXIT(("pFormat = 0x%x",pFormat));
1029 return pFormat;
1030
1031 error:
1032 #if !defined(DX_NATIVE_WINDOWS)
1033
1034 if(whereHostP)
1035 tdmFree(whereHostP);
1036 if(XserverP)
1037 tdmFree(XserverP);
1038 #endif
1039
1040 _dxfDeleteParsedDisplayString(pFormat);
1041
1042 EXIT(("ERROR: pFormat = NULL"));
1043 return NULL ;
1044 }
1045
1046 static Error
_validateDisplayString(tdmParsedFormatT * pFormat,int Pass)1047 _validateDisplayString(tdmParsedFormatT *pFormat, int Pass)
1048 {
1049 static char newDisplay[MAXHOSTNAMELEN + 31];
1050 /* DISPLAY=<hostname>:<10d>.<10d>\n */
1051
1052 ENTRY(("_validateDisplayString(0x%x)", pFormat));
1053
1054 BackingStore = TRUE;
1055 /* if 'type' does not start with 'X' we don't do HW rendering */
1056 if(pFormat->type[0] != 'X') {
1057 DXSetError(ERROR_BAD_PARAMETER, "invalid type %s", pFormat->type);
1058 goto error;
1059 }
1060 #if !defined(DX_NATIVE_WINDOWS)
1061 if(!pFormat->where) {
1062 /* no where parameter to Display() module, and no DISPLAY env var */
1063 DXSetError(ERROR_BAD_PARAMETER,
1064 "unable to determine where to create display window");
1065 goto error;
1066 }
1067 /*
1068 * We must have a 'where' by now, and is must be of the form
1069 * [hostname]:<number>[.<number>]
1070 */
1071 if((strlen(pFormat->where) == 0) ||
1072 strchr(pFormat->where,':') == NULL) {
1073 /* DISPLAY environment variable '%s' is not set or is invalid */
1074 DXSetError(ERROR_BAD_PARAMETER,"#13700",pFormat->where);
1075 goto error;
1076 }
1077
1078 /*
1079 * Are we attempting remote rendering? Can only do that using OpenGL or SGI GL.
1080 * Check on pass 2 so we know what graphics library we are using
1081 */
1082 if(Pass == 2 && !EQLSTR(pFormat->localHost,pFormat->fullHost)) {
1083 /*
1084 * If so, don't do BackingStore
1085 */
1086 BackingStore = FALSE;
1087
1088 #if !defined(sgi)
1089
1090 if (isOpenGL == 0) /* then we DID NOT load openGL and
1091 we can only do distributed rendering
1092 on an SGI
1093 */
1094 {
1095 DXSetError(ERROR_NOT_IMPLEMENTED, "Cannot do remote hardware rendering");
1096 goto error;
1097 }
1098 #endif
1099
1100 }
1101
1102 /* Make sure the DISPLAY env variable is set to what we intend to use */
1103 {
1104 char* env_dis = (char*)getenv("DISPLAY");
1105 if(env_dis && !EQLSTR(env_dis,pFormat->where))
1106 {
1107 /* reset the defaults DISPLAY */
1108 sprintf(newDisplay,"DISPLAY=%s",pFormat->where);
1109 putenv(newDisplay);
1110 }
1111 }
1112
1113 #endif
1114
1115 EXIT(("OK"));
1116 return OK;
1117 error:
1118
1119 EXIT(("ERROR"));
1120 return ERROR;
1121 }
1122
1123 /*
1124 * There are three ways for the graphics window to be deleted (and the
1125 * render instance to die).
1126 *
1127 * o The window manager kills the window, _dxfProcessEvents()
1128 * fields the notification and deletes the cache.
1129 * o _dxfProcessEvents() gets a WindowDestroy event and deletes the cache.
1130 * o The user or UI cause an executive `flushdictionary' command
1131 * to be executed, flushing the cache.
1132 *
1133 * Deleting the cache entry which references the tdm globals invokes
1134 * _dxfEndRenderModule() as a callback to cleanup window resources.
1135 * _dxfAsyncDelete() is no longer used to destroy the window; we now unmap
1136 * it instead.
1137 */
1138
1139 /*
1140 * This function is called each time the Display module
1141 * (i.e. the software renderer) determines that it will be
1142 * rendering the image. That is, whenever HW rendering is
1143 * not an attribute of the object
1144 */
1145 Error
_dxfAsyncDelete(char * where)1146 _dxfAsyncDelete (char *where)
1147 {
1148 char *cacheId ;
1149 Private cacheObject ;
1150 tdmChildGlobalP globals ;
1151 tdmParsedFormatT *format;
1152
1153 DEBUG_MARKER("_dxfAsyncDelete ENTRY");
1154 ENTRY(("_dxfAsyncDelete (\"%s\")",where));
1155
1156 if(!(format = _tdmParseDisplayString (where, &cacheId))) {
1157 EXIT(("ERROR"));
1158 DEBUG_MARKER("_dxfAsyncDelete EXIT");
1159 return ERROR;
1160 } else
1161 _dxfDeleteParsedDisplayString(format);
1162
1163 /* NOTE:
1164 * The only way for us to know if this window is doing HW rendering
1165 * is to look in the cache using the 'where' parameter. If we find
1166 * a match and the window is mapped, unmap it.
1167 *
1168 * If the entry is not in cache HW has never been done or the
1169 * instance has been deleted. In either case this is not an error.
1170 */
1171 if ((cacheObject = (Private) DXGetCacheEntry (cacheId, 0, 0))!=NULL) {
1172 globals = (tdmChildGlobalP) DXGetPrivateData(cacheObject) ;
1173 {
1174 DEFGLOBALDATA(globals) ;
1175 /* delete the reference created by DXGetCacheEntry() */
1176 DXDelete((Pointer)cacheObject) ;
1177
1178 if (MAPPED) {
1179 /* unmap the graphics window */
1180 PRINT(("unmapping window %d", XWINID));
1181 #if !defined(DX_NATIVE_WINDOWS)
1182
1183 XUnmapWindow(DPY, XWINID) ;
1184 XFlush(DPY) ;
1185 #endif
1186
1187 MAPPED = 0 ;
1188 }
1189 }
1190 } else {
1191 PRINT(("instance not in cache"));
1192 }
1193
1194 tdmFree(cacheId) ;
1195 EXIT(("OK"));
1196 DEBUG_MARKER("_dxfAsyncDelete EXIT");
1197 return OK ;
1198 }
1199
1200 static char*
_token(char * str,char * delimit,char * chaff,int inPlace)1201 _token(char* str, char* delimit, char* chaff, int inPlace)
1202 {
1203 /* Find the end of the first token */
1204 int offset;
1205 static char *savedStr;
1206 char *ret;
1207 int tmp;
1208
1209 /*
1210 * This gets called a lot so don't trace it...
1211 * ENTRY(("_token(\"%s\", \"%s\", \"%s\", %d)",
1212 * str, delimit, chaff, inPlace));
1213 */
1214
1215 if(!str && !savedStr) {
1216 /* EXIT(("!str && !savedStr")); */
1217 return NULL;
1218 }
1219
1220 if(!str)
1221 str = savedStr;
1222
1223 offset = strcspn(str,delimit);
1224 savedStr = str + (offset + (int)(str[offset] != '\0')) ;
1225
1226 /* create the return pointer */
1227 if(inPlace) {
1228 ret = str;
1229 ret[offset] = '\0';
1230 tmp = strspn(ret,chaff);
1231 ret += tmp;
1232 ret[strcspn(ret,chaff)] = '\0' ;
1233 } else {
1234 if(!(ret = tdmAllocate(offset+1))) {
1235 /* EXIT(("tdmAllocate failed")); */
1236 return NULL;
1237 }
1238 strncpy(ret,str,offset);
1239 ret[offset] = '\0';
1240 tmp = strspn(ret,chaff);
1241 if(tmp)
1242 strcpy(ret,ret+tmp); /* Move the text to the front of ret */
1243 ret[strcspn(ret,chaff)] = '\0' ;
1244 }
1245
1246 /* EXIT(("ret = \"%s\"",ret)); */
1247 return ret;
1248 }
1249
1250 static char*
_getFullHostName(char * givenName)1251 _getFullHostName(char* givenName)
1252 {
1253 char shortName[MAXHOSTNAMELEN+1];
1254 struct hostent *h_ent;
1255 char *ret;
1256
1257 ENTRY(("_getFullHostName(\"%s\")",givenName));
1258
1259 if(!givenName) {
1260 EXIT(("givenName == NULL"));
1261 return NULL;
1262 }
1263
1264 /*
1265 * Get the short version of the host name
1266 */
1267 if(EQLSTR(givenName,"") ||
1268 EQLSTR(givenName,"unix") ||
1269 EQLSTR(givenName,"localhost")) {
1270 if(gethostname(shortName,MAXHOSTNAMELEN)) {
1271 strcpy(shortName,givenName);
1272 }
1273 } else {
1274 strcpy(shortName,givenName);
1275 }
1276
1277 /*
1278 * XXX Should check for dotted decimal notation here
1279 */
1280
1281 /*
1282 * Get the full name
1283 */
1284 h_ent = gethostbyname(shortName);
1285 if (! h_ent) {
1286 h_ent = gethostbyname(shortName);
1287 if (! h_ent) {
1288 unsigned long inaddr;
1289 inaddr = inet_addr(shortName);
1290 if (inaddr != -1)
1291 h_ent = gethostbyaddr((char *)&inaddr, sizeof(unsigned long), AF_INET);
1292 }
1293 }
1294
1295 if (h_ent) {
1296 ret = tdmAllocate(strlen(h_ent->h_name)+1);
1297 if (! ret)
1298 return NULL;
1299
1300 strcpy(ret,h_ent->h_name);
1301 } else {
1302 ret = tdmAllocate(strlen(shortName) + 1);
1303 if (! ret)
1304 return NULL;
1305
1306 strcpy(ret,shortName);
1307 }
1308
1309 EXIT(("ret = \"%s\"",ret));
1310 return ret;
1311 }
1312
1313 static char*
_getFullXserver(char * givenXserver)1314 _getFullXserver(char* givenXserver)
1315 {
1316 char* ret;
1317
1318 ENTRY(("_getFullXserver(\"%s\")",givenXserver));
1319
1320 if(!strchr(givenXserver,':')) {
1321 if(!strchr(givenXserver,'.')) {
1322 ret = tdmAllocate(strlen(givenXserver)+4);
1323 if (!ret)
1324 goto error;
1325 strcpy(ret,":");
1326 strcat(ret,givenXserver);
1327 strcat(ret,".0");
1328 } else {
1329 ret = tdmAllocate(strlen(givenXserver)+2);
1330 if (!ret)
1331 goto error;
1332 strcpy(ret,":");
1333 strcat(ret,givenXserver);
1334 }
1335 } else {
1336 if(!strchr(givenXserver,'.')) {
1337 ret = tdmAllocate(strlen(givenXserver)+3);
1338 if (!ret)
1339 goto error;
1340 strcpy(ret,givenXserver);
1341 strcat(ret,".0");
1342 } else {
1343 ret = tdmAllocate(strlen(givenXserver)+1);
1344 if (!ret)
1345 goto error;
1346 strcpy(ret,givenXserver);
1347 }
1348 }
1349
1350 EXIT(("ret = \"%s\"",ret));
1351 return ret;
1352
1353 error:
1354 EXIT(("ERROR"));
1355 return NULL;
1356 }
1357
1358 static hwFlagsT servicesFlags = 0;
1359
1360 hwFlags
_dxf_SERVICES_FLAGS()1361 _dxf_SERVICES_FLAGS()
1362 {
1363 return &servicesFlags;
1364 }
1365
1366 void *
_dxfGetStereoWindowInfo(char * where,void * lwi,void * rwi)1367 _dxfGetStereoWindowInfo(char *where, void *lwi, void *rwi)
1368 {
1369 Private cacheObject = NULL;
1370 tdmChildGlobalP globals = NULL;
1371 char* cacheId = NULL;
1372 tdmParsedFormatT* pFormat = NULL;
1373
1374 /*
1375 * get host and window name from display string, fill in the cache id
1376 */
1377 if (!(pFormat = _tdmParseDisplayString (where, &cacheId)))
1378 goto error;
1379
1380 /*
1381 * validate the display string
1382 */
1383 if (!(_validateDisplayString(pFormat, 1)))
1384 goto error ;
1385
1386 /*
1387 * Get a pointer to the global data
1388 */
1389 cacheObject = (Private) DXGetCacheEntry(cacheId, 0, 0);
1390 if (! cacheObject) {
1391 DXSetError(ERROR_BAD_PARAMETER,
1392 "window matching \"%s\" not found", where);
1393 goto error;
1394 } else {
1395 globals = (tdmChildGlobalP) DXGetPrivateData(cacheObject) ;
1396 {
1397 DEFGLOBALDATA(globals) ;
1398 if (lwi)
1399 *(WindowInfo *)lwi = LEFTWINDOWINFO;
1400 if (rwi)
1401 *(WindowInfo *)rwi = RIGHTWINDOWINFO;
1402 }
1403 }
1404
1405 return (void *)globals;
1406
1407 error:
1408 if (pFormat)
1409 _dxfDeleteParsedDisplayString(pFormat);
1410
1411 if (cacheId)
1412 tdmFree(cacheId);
1413
1414 if(cacheObject)
1415 DXDelete((Pointer)cacheObject) ;
1416
1417 return NULL;
1418 }
1419
1420