1 /* grMain.c -
2  *
3  *     *********************************************************************
4  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
5  *     * Permission to use, copy, modify, and distribute this              *
6  *     * software and its documentation for any purpose and without        *
7  *     * fee is hereby granted, provided that the above copyright          *
8  *     * notice appear in all copies.  The University of California        *
9  *     * makes no representations about the suitability of this            *
10  *     * software for any purpose.  It is provided "as is" without         *
11  *     * express or implied warranty.  Export of this software outside     *
12  *     * of the United States of America may require an export license.    *
13  *     *********************************************************************
14  *
15  * This file contains a few core variables and routines for
16  * manipulating color graphics displays.  Its main function is
17  * to provide a central dispatch point to various routines for
18  * different display types.
19  */
20 
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/graphics/grMain.c,v 1.4 2010/06/24 12:37:18 tim Exp $";
23 #endif  /* not lint */
24 
25 /*
26  * The following display types are currently suported by Magic:
27  *
28  *	NULL		A null device for running Magic without using
29  *			a graphics display.  This device does nothing
30  *			when its routines are called.
31  *
32  *	X11		A port to the X11 window system, based on the Stanford
33  *	XWIND		X10 driver, mods done at Brown University, an X11 port
34  *			done at the University of Washington, and the X10a
35  *			driver from Lawrence Livermore Labs.  This driver was
36  *			developed by Don Stark (Stanford & decwrl).
37  *	8BIT		X11 driver, force 8-bit graphics mode.
38  *	16BIT		X11 driver, force 16-bit graphics mode.
39  *	24BIT		X11 driver, force 24-bit graphics mode.
40  *
41  *	OpenGL		A port to OpenGL or Mesa.  Developed by Tim Edwards
42  *			(Johns Hopkins University Applied Physics Lab)
43  *
44  * To port Magic to another type of display, you need to add its name to
45  * the table 'grDisplayTypes' and then add a pointer to an initialization
46  * routine to 'grInitProcs'.  The initialization routine will fill in all
47  * of the graphics routine pointers so that they point to procedures that
48  * can handle the new display type.  All calls to device-specific
49  * procedures are made by indirecting through these pointers.
50  */
51 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sys/types.h>
56 #include <sys/time.h>
57 #include <errno.h>
58 #include <ctype.h>
59 
60 #include "utils/magic.h"
61 #include "utils/magsgtty.h"
62 #include "textio/textio.h"
63 #include "utils/geometry.h"
64 #include "utils/hash.h"
65 #include "windows/windows.h"
66 #include "graphics/graphics.h"
67 #include "graphics/graphicsInt.h"
68 
69 #define FAVORITE_DISPLAY	"NULL"	/* Default display type */
70 
71 /* Correction between real-valued coordinate systems and pixel-based
72  * coordinate systems, which can disagree by a pixel on the width of
73  * polygons and position of lines.
74  */
75 global int GrPixelCorrect = 1;
76 
77 /* The following rectangle is describes the display area and is available
78  * to the user of this module.
79  */
80 global Rect GrScreenRect = {0, 0, 0, 0};
81 
82 /*
83  * Interrupt status for the timer.  In TCL, this is used for graphics
84  * interrupts to periodically check the X11 queue for pending events.
85  * In both TCL and non-TCL versions, it can be used for a general-
86  * purpose interrupt timer.
87  */
88 global unsigned char GrDisplayStatus = DISPLAY_IDLE;
89 
90 /* The first of the following tables defines the legal
91  * display types and the second table defines an
92  * initialization routine for each type.
93  *
94  * These entries MUST be all upper case, since what the user types will
95  * be converted to upper case before comparison.
96  */
97 
98 static char *grDisplayTypes[] = {
99 #ifdef	X11
100     "XWIND",
101     "X11",
102     "8BIT",
103     "16BIT",
104     "24BIT",
105 #endif
106 #ifdef  OGL
107     "OPEN_GL",
108     "OGL",
109     "OPENGL",
110 #endif
111 #ifdef CAIRO
112     "CAIRO",
113     "XR",
114 #endif
115     "NULL",
116     NULL};
117 
118 extern bool x11SetDisplay();
119 extern bool oglSetDisplay();
120 extern bool nullSetDisplay();
121 extern bool cairoSetDisplay();
122 
123 static bool (*(grInitProcs[]))() = {
124 #ifdef	X11
125     x11SetDisplay,
126     x11SetDisplay,
127     x11SetDisplay,
128     x11SetDisplay,
129     x11SetDisplay,
130 #endif	/* X11 */
131 #ifdef  OGL
132     oglSetDisplay,
133     oglSetDisplay,
134     oglSetDisplay,
135 #endif
136 #ifdef CAIRO
137     cairoSetDisplay,
138     cairoSetDisplay,
139 #endif
140     nullSetDisplay,
141     NULL};
142 
143 /* The following variables are pointers to the various graphics
144  * procedures.  The macros in graphics.h cause these pointers
145  * to be indirected through when calls occur to graphics procedures.
146  * This indirection allows for several display types to be supported
147  * by a single version of Magic.  The pointers are initially NULL,
148  * but are rewritten by the various graphics initializers.
149  */
150 
151 void (*GrLockPtr)()		= NULL;
152 void (*GrUnlockPtr)()		= NULL;
153 bool (*GrInitPtr)()		= NULL;
154 void (*GrClosePtr)()		= NULL;
155 void (*GrSetCMapPtr)()		= NULL;
156 
157 void (*GrSetCursorPtr)()	= NULL;
158 void (*GrTextSizePtr)()		= NULL;
159 void (*GrDrawGlyphPtr)()	= NULL;
160 void (*GrBitBltPtr)()		= NULL;
161 int  (*GrReadPixelPtr)()	= NULL;
162 void (*GrFlushPtr)()		= NULL;
163 bool (*GrCreateWindowPtr)()	= NULL;
164 void (*GrDeleteWindowPtr)()	= NULL;
165 void (*GrConfigureWindowPtr)()	= NULL;
166 void (*GrOverWindowPtr)()	= NULL;
167 void (*GrUnderWindowPtr)()	= NULL;
168 void (*GrDamagedPtr)()		= NULL;
169 void (*GrUpdateIconPtr)()   	= NULL;
170 bool (*GrEventPendingPtr)()   	= NULL;
171 int (*GrWindowIdPtr)()   	= NULL;
172 char *(*GrWindowNamePtr)()	= NULL;
173 bool (*GrGetCursorPosPtr)()   	= NULL;
174 bool (*GrGetCursorRootPosPtr)()	= NULL;
175 
176 void (*GrEnableTabletPtr)()	= NULL;
177 void (*GrDisableTabletPtr)()	= NULL;
178 
179 bool (*GrGetBackingStorePtr)() 	  = NULL;
180 bool (*GrScrollBackingStorePtr)() = NULL;
181 void (*GrPutBackingStorePtr)() 	  = NULL;
182 void (*GrFreeBackingStorePtr)()   = NULL;
183 void (*GrCreateBackingStorePtr)() = NULL;
184 
185 /* variables similar to the above, except that they are only used
186  * internal to the graphics package
187  */
188 void (*grPutTextPtr)()		= NULL;
189 void (*grFontTextPtr)()		= NULL;
190 void (*grGetCharSizePtr)()	= NULL;
191 void (*grSetSPatternPtr)()	= NULL;
192 void (*grDefineCursorPtr)()	= NULL;
193 void (*grFreeCursorPtr)()	= NULL;
194 bool (*grDrawGridPtr)()		= NULL;
195 void (*grDrawLinePtr)()		= NULL;
196 void (*grSetWMandCPtr)()	= NULL;
197 void (*grFillRectPtr)()		= NULL;
198 void (*grSetStipplePtr)()	= NULL;
199 void (*grSetLineStylePtr)()	= NULL;
200 void (*grSetCharSizePtr)()	= NULL;
201 void (*grFillPolygonPtr)()      = NULL;
202 
203 /* The following variables are set by initialization routines for the
204  * various displays.  They are strings that indicate what kind of
205  * dstyle, cmap and cursor files should be used for this display.  Almost
206  * all of the displays are happy with the default values given below.
207  * Note:  a NULL grCMapType means that this display doesn't need a
208  * color map (it's black-and-white).
209  */
210 
211 char *grDStyleType = "7bit";
212 char *grCMapType = "7bit";
213 char *grCursorType = "bw";
214 
215 int grNumBitPlanes = 0;      /* Number of bit-planes we are using. */
216 int grBitPlaneMask = 0;      /* Mask of the valid bit-plane bits. */
217 
218 /* Procedures called just before and after Magic is suspended (via ^Z). */
219 extern void grNullProc();
220 void (*GrStopPtr)() = grNullProc;
221 void (*GrResumePtr)() = grNullProc;
222 
223 
224 /*---------------------------------------------------------
225  * GrSetDisplay --
226  *	This routine sets a display type, opens files,  and initializes the
227  *	display.
228  *
229  * Results:
230  *	TRUE is returned if the display was found and initialized
231  *	successfully.  If the type didn't register, or the file is
232  *	NULL, then FALSE is returned.
233  *
234  * Side Effects:
235  *	Tables are set up to control which display routines are
236  *	used when communcating with the display.  The display
237  *	is initialized and made ready for action.
238  *---------------------------------------------------------
239  */
240 
241 bool
GrSetDisplay(type,outName,mouseName)242 GrSetDisplay(type, outName, mouseName)
243 char *type;			/* Name of the display type. */
244 char *outName;			/* Filename used for communciation with
245 				 * display. */
246 char *mouseName;		/* Filename used for communciation
247 				 * with tablet. */
248 
249 {
250     char **ptr;
251     char *cp;
252     int i;
253     bool res;
254 
255     if (outName == NULL)
256     {
257 	TxError("No graphics device specified.\n");
258 	return FALSE;
259     }
260     if (mouseName == NULL)
261     {
262 	TxError("No mouse specified.\n");
263 	return FALSE;
264     }
265 
266     /* Skip any white space */
267     while (isspace(*type)) type++;
268 
269     /* Convert display type to upper case. */
270     for (cp = type; *cp; cp++) { if (islower(*cp)) *cp = toupper(*cp); }
271 
272     /* See if the display type is in our table. */
273     ptr = grDisplayTypes;
274     for (i = 0; *ptr; i++)
275     {
276 	if (strncmp(*ptr, type, strlen(*ptr)) == 0) break;
277 	ptr++;
278     }
279 
280     /* Did we find it? */
281     if (*ptr == NULL)
282     {
283 	TxError("Unknown display type:  %s\n", type);
284  	TxError("These display types are available in this version of Magic:\n");
285 	ptr = grDisplayTypes;
286 	for (i = 0; *ptr; i++)
287 	{
288 	    TxError("        %s\n", *ptr);
289 	    ptr++;
290 	}
291 	TxError("Use '-d NULL' if you don't need graphics.\n");
292 	return FALSE;
293     }
294 
295     /* Call the initialization procedure. */
296     res = (*(grInitProcs[i]))(type, outName, mouseName);
297     if (!res)
298     {
299 	TxError("The graphics display couldn't be correctly initialized.\n");
300 	TxError("Use '-d NULL' if you don't need graphics.\n");
301     }
302     return res;
303 }
304 
305 /*
306  * ----------------------------------------------------------------------------
307  *
308  * GrIsDisplay --
309  *
310  *	Check if the first argument is the same type of display as the
311  *	second argument.
312  *
313  * Results:
314  *	TRUE if both strings represent the same display type, FALSE
315  *	otherwise.  "same display type" is defined as both display
316  *	strings in the grDisplayTypes list corresponding to the same
317  *	initialization procedure in grInitProcs.
318  *
319  * Side Effects:
320  *	None.
321  *
322  * ----------------------------------------------------------------------------
323  */
324 bool
GrIsDisplay(disp1,disp2)325 GrIsDisplay(disp1, disp2)
326     char *disp1, *disp2;
327 {
328     char **ptr1, **ptr2;
329     int i, j;
330 
331     /* See if the display type is in our table. */
332     ptr1 = grDisplayTypes;
333     for (i = 0; *ptr1; i++)
334     {
335 	if (strncmp(*ptr1, disp1, strlen(*ptr1)) == 0) break;
336 	ptr1++;
337     }
338     if (*ptr1 == NULL)
339     {
340 	TxError("Unknown display type:  %s\n", disp1);
341 	return FALSE;
342     }
343 
344     ptr2 = grDisplayTypes;
345     for (j = 0; *ptr2; j++)
346     {
347 	if (strncmp(*ptr2, disp2, strlen(*ptr2)) == 0) break;
348 	ptr2++;
349     }
350     if (*ptr2 == NULL)
351     {
352 	TxError("Unknown display type:  %s\n", disp2);
353 	return FALSE;
354     }
355 
356     if (grInitProcs[i] == grInitProcs[j]) return TRUE;
357     return FALSE;
358 }
359 
360 
361 /*
362  * ----------------------------------------------------------------------------
363  * GrGuessDisplayType --
364  *
365  *	Try to guess what sort of machine we are on, and set the display
366  *	ports and type appropriately.  This info is overridden by
367  *	$CAD_ROOT/magic/displays and by command line switches.
368  *
369  * Results:
370  *	None.
371  *
372  * Side effects:
373  *	Modifies the strings passed in.
374  * ----------------------------------------------------------------------------
375  */
376 
377 void
GrGuessDisplayType(graphics,mouse,display,monitor)378 GrGuessDisplayType(graphics, mouse, display, monitor)
379     char **graphics;		/* default device for sending out graphics */
380     char **mouse;		/* default device for reading mouse (tablet) */
381     char **display;		/* default type of device (OGL, etc...) */
382     char **monitor;		/* default type of monitor (pale, std) */
383 {
384     bool onSun;			/* Are we on a Sun? */
385     bool haveX;			/* are we running under X? */
386     char **ptr;
387 
388     *graphics = NULL;
389     *mouse = NULL;
390     *display = NULL;
391     *monitor = "std";
392 
393     /* Check for signs of suntools. */
394     onSun = (access("/dev/win0", 0) == 0);
395     haveX = (getenv("DISPLAY") != NULL);
396 
397     if (haveX)
398     {
399 	*mouse = *graphics = NULL;
400 	*display = "XWIND";
401     }
402     else if (onSun) {
403 	TxError("You are on a Sun but not running X.\n");
404 	*mouse = *graphics = NULL;
405 	*display = "NULL";
406     }
407     else {
408 	/* GUESS:  who knows, maybe a VAX? */
409 	*mouse = *graphics = NULL;
410 	*display = FAVORITE_DISPLAY;
411     }
412 
413     /* If the guessed value is NOT in the known list of display types, then */
414     /* choose the first display type in the list.	---Tim 3/13/00	    */
415 
416     ptr = grDisplayTypes;
417     while ((*ptr != *display) && (*ptr != NULL)) ptr++;
418     if ((*ptr == NULL) && (ptr != grDisplayTypes)) {
419         ptr = grDisplayTypes;
420 	*display = *ptr;
421     }
422 }
423 
424 
425 /*
426  * ----------------------------------------------------------------------------
427  * grFgets --
428  *
429  *	Just like fgets, except that it times out after 20 seconds, and prints
430  *	a warning message.  After one second a warning message is also
431  *	printed.
432  *
433  * Results:
434  *	Pointer to the string returned by fgets (equal to the 1st argument)
435  *
436  * Side effects:
437  *	None.
438  * ----------------------------------------------------------------------------
439  */
440 
441 char *
grFgets(str,n,stream,name)442 grFgets(str, n, stream, name)
443     char *str;
444     int n;
445     FILE *stream;
446     char *name;		/* The user name of the stream, for the error msg */
447 {
448     fd_set fn;
449     char *newstr;
450     struct timeval threeSec, twentySecs;
451 
452     threeSec.tv_sec = 3;
453     threeSec.tv_usec = 0;
454     twentySecs.tv_sec = 20;
455     twentySecs.tv_usec = 0;
456 
457     FD_ZERO(&fn);
458     FD_SET(fileno(stream), &fn);
459     newstr = str;
460     n--;
461     if (n < 0) return (char *) NULL;
462 
463     while (n > 0)
464     {
465 	fd_set f;
466 	char ch;
467         int sel;
468 
469 	f = fn;
470 	sel = select(TX_MAX_OPEN_FILES, &f, (fd_set *) NULL, (fd_set *) NULL, &threeSec);
471 	if  (sel == 0)
472 	{
473 	    TxError("The %s is responding slowly, or not at all.\n", name);
474 	    TxError("I'll wait for 20 seconds and then give up.\n");
475 	    f = fn;
476 	    sel = select(TX_MAX_OPEN_FILES, &f, (fd_set *) NULL,
477 			(fd_set *) NULL, &twentySecs);
478 	    if (sel == 0)
479 	    {
480 		TxError("The %s did not respond.\n", name);
481 		return (char *) NULL;
482 	    }
483 	    else if (sel < 0)
484 	    {
485 		if (errno == EINTR) {
486 		    TxError("Timeout aborted.\n");
487 		}
488 		else
489 		{
490 		    perror("magic");
491 		    TxError("Error in reading the %s\n", name);
492 		}
493 		return (char *) NULL;
494 	    }
495 	    else
496 		TxError("The %s finally responded.\n", name);
497 	}
498 	else if (sel < 0)
499 	{
500 	    if (errno != EINTR)
501 	    {
502 		perror("magic");
503 		TxError("Error in reading the %s\n", name);
504 		return (char *) NULL;
505 	    }
506 	    /* else try again, back to top of the loop */
507 	    continue;
508 	}
509 
510 	ch = getc(stream);
511 	*newstr = ch;
512 	n--;
513 	newstr++;
514 	if (ch == '\n')
515 	    break;
516     }
517 
518     *newstr = '\0';
519     return str;
520 }
521 
522 
523 /*---------------------------------------------------------------------------
524  * grNullProc --
525  *
526  *	A procedure of the type 'void' that does absolutely nothing.
527  *	Used when we need to point a procedure pointer to something, but
528  *	don't want it to do anything.
529  *
530  * Results:
531  *	None.
532  *
533  * Side Effects:
534  *	None.
535  *
536  *----------------------------------------------------------------------------
537  */
538 
539 void
grNullProc()540 grNullProc()
541 {
542 }
543