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