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