/* grMain.c - * * ********************************************************************* * * Copyright (C) 1985, 1990 Regents of the University of California. * * * Permission to use, copy, modify, and distribute this * * * software and its documentation for any purpose and without * * * fee is hereby granted, provided that the above copyright * * * notice appear in all copies. The University of California * * * makes no representations about the suitability of this * * * software for any purpose. It is provided "as is" without * * * express or implied warranty. Export of this software outside * * * of the United States of America may require an export license. * * ********************************************************************* * * This file contains a few core variables and routines for * manipulating color graphics displays. Its main function is * to provide a central dispatch point to various routines for * different display types. */ #ifndef lint 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 $"; #endif /* not lint */ /* * The following display types are currently suported by Magic: * * NULL A null device for running Magic without using * a graphics display. This device does nothing * when its routines are called. * * X11 A port to the X11 window system, based on the Stanford * XWIND X10 driver, mods done at Brown University, an X11 port * done at the University of Washington, and the X10a * driver from Lawrence Livermore Labs. This driver was * developed by Don Stark (Stanford & decwrl). * 8BIT X11 driver, force 8-bit graphics mode. * 16BIT X11 driver, force 16-bit graphics mode. * 24BIT X11 driver, force 24-bit graphics mode. * * OpenGL A port to OpenGL or Mesa. Developed by Tim Edwards * (Johns Hopkins University Applied Physics Lab) * * To port Magic to another type of display, you need to add its name to * the table 'grDisplayTypes' and then add a pointer to an initialization * routine to 'grInitProcs'. The initialization routine will fill in all * of the graphics routine pointers so that they point to procedures that * can handle the new display type. All calls to device-specific * procedures are made by indirecting through these pointers. */ #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #include #include /* C99 compat */ #include #include "utils/magic.h" #include "utils/magsgtty.h" #include "textio/textio.h" #include "utils/geometry.h" #include "utils/hash.h" #include "windows/windows.h" #include "graphics/graphics.h" #include "graphics/graphicsInt.h" #define FAVORITE_DISPLAY "NULL" /* Default display type */ /* Correction between real-valued coordinate systems and pixel-based * coordinate systems, which can disagree by a pixel on the width of * polygons and position of lines. */ global int GrPixelCorrect = 1; /* The following rectangle is describes the display area and is available * to the user of this module. */ global Rect GrScreenRect = {{0, 0}, {0, 0}}; /* * Interrupt status for the timer. In TCL, this is used for graphics * interrupts to periodically check the X11 queue for pending events. * In both TCL and non-TCL versions, it can be used for a general- * purpose interrupt timer. */ global unsigned char GrDisplayStatus = DISPLAY_IDLE; /* The first of the following tables defines the legal * display types and the second table defines an * initialization routine for each type. * * These entries MUST be all upper case, since what the user types will * be converted to upper case before comparison. */ static char *grDisplayTypes[] = { #ifdef X11 "XWIND", "X11", "8BIT", "16BIT", "24BIT", #endif #ifdef OGL "OPEN_GL", "OGL", "OPENGL", #endif #ifdef CAIRO "CAIRO", "XR", #endif "NULL", NULL}; extern bool x11SetDisplay(); extern bool oglSetDisplay(); extern bool nullSetDisplay(); extern bool cairoSetDisplay(); static bool (*(grInitProcs[]))() = { #ifdef X11 x11SetDisplay, x11SetDisplay, x11SetDisplay, x11SetDisplay, x11SetDisplay, #endif /* X11 */ #ifdef OGL oglSetDisplay, oglSetDisplay, oglSetDisplay, #endif #ifdef CAIRO cairoSetDisplay, cairoSetDisplay, #endif nullSetDisplay, NULL}; /* The following variables are pointers to the various graphics * procedures. The macros in graphics.h cause these pointers * to be indirected through when calls occur to graphics procedures. * This indirection allows for several display types to be supported * by a single version of Magic. The pointers are initially NULL, * but are rewritten by the various graphics initializers. */ void (*GrLockPtr)() = NULL; void (*GrUnlockPtr)() = NULL; bool (*GrInitPtr)() = NULL; void (*GrClosePtr)() = NULL; void (*GrSetCMapPtr)() = NULL; void (*GrSetCursorPtr)() = NULL; int (*GrTextSizePtr)() = NULL; void (*GrDrawGlyphPtr)() = NULL; void (*GrBitBltPtr)() = NULL; int (*GrReadPixelPtr)() = NULL; void (*GrFlushPtr)() = NULL; bool (*GrCreateWindowPtr)() = NULL; void (*GrDeleteWindowPtr)() = NULL; void (*GrConfigureWindowPtr)() = NULL; void (*GrOverWindowPtr)() = NULL; void (*GrUnderWindowPtr)() = NULL; void (*GrDamagedPtr)() = NULL; void (*GrUpdateIconPtr)() = NULL; bool (*GrEventPendingPtr)() = NULL; int (*GrWindowIdPtr)() = NULL; char *(*GrWindowNamePtr)() = NULL; bool (*GrGetCursorPosPtr)() = NULL; bool (*GrGetCursorRootPosPtr)() = NULL; void (*GrEnableTabletPtr)() = NULL; void (*GrDisableTabletPtr)() = NULL; bool (*GrGetBackingStorePtr)() = NULL; bool (*GrScrollBackingStorePtr)() = NULL; void (*GrPutBackingStorePtr)() = NULL; void (*GrFreeBackingStorePtr)() = NULL; void (*GrCreateBackingStorePtr)() = NULL; /* variables similar to the above, except that they are only used * internal to the graphics package */ void (*grPutTextPtr)() = NULL; void (*grFontTextPtr)() = NULL; void (*grGetCharSizePtr)() = NULL; void (*grSetSPatternPtr)() = NULL; void (*grDefineCursorPtr)() = NULL; void (*grFreeCursorPtr)() = NULL; bool (*grDrawGridPtr)() = NULL; void (*grDrawLinePtr)() = NULL; void (*grSetWMandCPtr)() = NULL; void (*grFillRectPtr)() = NULL; void (*grSetStipplePtr)() = NULL; void (*grSetLineStylePtr)() = NULL; void (*grSetCharSizePtr)() = NULL; void (*grFillPolygonPtr)() = NULL; /* The following variables are set by initialization routines for the * various displays. They are strings that indicate what kind of * dstyle, cmap and cursor files should be used for this display. Almost * all of the displays are happy with the default values given below. * Note: a NULL grCMapType means that this display doesn't need a * color map (it's black-and-white). */ char *grDStyleType = "7bit"; char *grCMapType = "7bit"; char *grCursorType = "bw"; int grNumBitPlanes = 0; /* Number of bit-planes we are using. */ int grBitPlaneMask = 0; /* Mask of the valid bit-plane bits. */ /* Procedures called just before and after Magic is suspended (via ^Z). */ extern void grNullProc(); void (*GrStopPtr)() = grNullProc; void (*GrResumePtr)() = grNullProc; /*--------------------------------------------------------- * GrSetDisplay -- * This routine sets a display type, opens files, and initializes the * display. * * Results: * TRUE is returned if the display was found and initialized * successfully. If the type didn't register, or the file is * NULL, then FALSE is returned. * * Side Effects: * Tables are set up to control which display routines are * used when communcating with the display. The display * is initialized and made ready for action. *--------------------------------------------------------- */ bool GrSetDisplay(type, outName, mouseName) char *type; /* Name of the display type. */ char *outName; /* Filename used for communciation with * display. */ char *mouseName; /* Filename used for communciation * with tablet. */ { char **ptr; char *cp; int i; bool res; if (outName == NULL) { TxError("No graphics device specified.\n"); return FALSE; } if (mouseName == NULL) { TxError("No mouse specified.\n"); return FALSE; } /* Skip any white space */ while (isspace(*type)) type++; /* Convert display type to upper case. */ for (cp = type; *cp; cp++) { if (islower(*cp)) *cp = toupper(*cp); } /* See if the display type is in our table. */ ptr = grDisplayTypes; for (i = 0; *ptr; i++) { if (strncmp(*ptr, type, strlen(*ptr)) == 0) break; ptr++; } /* Did we find it? */ if (*ptr == NULL) { TxError("Unknown display type: %s\n", type); TxError("These display types are available in this version of Magic:\n"); ptr = grDisplayTypes; for (i = 0; *ptr; i++) { TxError(" %s\n", *ptr); ptr++; } TxError("Use '-d NULL' if you don't need graphics.\n"); return FALSE; } /* Call the initialization procedure. */ res = (*(grInitProcs[i]))(type, outName, mouseName); if (!res) { TxError("The graphics display couldn't be correctly initialized.\n"); TxError("Use '-d NULL' if you don't need graphics.\n"); } return res; } /* * ---------------------------------------------------------------------------- * * GrIsDisplay -- * * Check if the first argument is the same type of display as the * second argument. * * Results: * TRUE if both strings represent the same display type, FALSE * otherwise. "same display type" is defined as both display * strings in the grDisplayTypes list corresponding to the same * initialization procedure in grInitProcs. * * Side Effects: * None. * * ---------------------------------------------------------------------------- */ bool GrIsDisplay(disp1, disp2) char *disp1, *disp2; { char **ptr1, **ptr2; int i, j; /* See if the display type is in our table. */ ptr1 = grDisplayTypes; for (i = 0; *ptr1; i++) { if (strncmp(*ptr1, disp1, strlen(*ptr1)) == 0) break; ptr1++; } if (*ptr1 == NULL) { TxError("Unknown display type: %s\n", disp1); return FALSE; } ptr2 = grDisplayTypes; for (j = 0; *ptr2; j++) { if (strncmp(*ptr2, disp2, strlen(*ptr2)) == 0) break; ptr2++; } if (*ptr2 == NULL) { TxError("Unknown display type: %s\n", disp2); return FALSE; } if (grInitProcs[i] == grInitProcs[j]) return TRUE; return FALSE; } /* * ---------------------------------------------------------------------------- * GrGuessDisplayType -- * * Try to guess what sort of machine we are on, and set the display * ports and type appropriately. This info is overridden by * $CAD_ROOT/magic/displays and by command line switches. * * Results: * None. * * Side effects: * Modifies the strings passed in. * ---------------------------------------------------------------------------- */ void GrGuessDisplayType(graphics, mouse, display, monitor) char **graphics; /* default device for sending out graphics */ char **mouse; /* default device for reading mouse (tablet) */ char **display; /* default type of device (OGL, etc...) */ char **monitor; /* default type of monitor (pale, std) */ { bool onSun; /* Are we on a Sun? */ bool haveX; /* are we running under X? */ char **ptr; *graphics = NULL; *mouse = NULL; *display = NULL; *monitor = "std"; /* Check for signs of suntools. */ onSun = (access("/dev/win0", 0) == 0); haveX = (getenv("DISPLAY") != NULL); if (haveX) { *mouse = *graphics = NULL; *display = "XWIND"; } else if (onSun) { TxError("You are on a Sun but not running X.\n"); *mouse = *graphics = NULL; *display = "NULL"; } else { /* GUESS: who knows, maybe a VAX? */ *mouse = *graphics = NULL; *display = FAVORITE_DISPLAY; } /* If the guessed value is NOT in the known list of display types, then */ /* choose the first display type in the list. ---Tim 3/13/00 */ ptr = grDisplayTypes; while ((*ptr != *display) && (*ptr != NULL)) ptr++; if ((*ptr == NULL) && (ptr != grDisplayTypes)) { ptr = grDisplayTypes; *display = *ptr; } } /* * ---------------------------------------------------------------------------- * grFgets -- * * Just like fgets, except that it times out after 20 seconds, and prints * a warning message. After one second a warning message is also * printed. * * Results: * Pointer to the string returned by fgets (equal to the 1st argument) * * Side effects: * None. * ---------------------------------------------------------------------------- */ char * grFgets(str, n, stream, name) char *str; int n; FILE *stream; char *name; /* The user name of the stream, for the error msg */ { fd_set fn; char *newstr; struct timeval threeSec, twentySecs; threeSec.tv_sec = 3; threeSec.tv_usec = 0; twentySecs.tv_sec = 20; twentySecs.tv_usec = 0; const int fd = fileno(stream); ASSERT(fd >= 0 && fd < FD_SETSIZE, "fd>=0&&fd= FD_SETSIZE) { TxError("WARNING: grFgets(fd=%d) called with fd out of range 0..%d\n", fd, FD_SETSIZE-1); return NULL; /* allowing things to continue is UB */ } FD_ZERO(&fn); FD_SET(fd, &fn); newstr = str; n--; if (n < 0) return (char *) NULL; while (n > 0) { fd_set f; char ch; int sel; f = fn; sel = select(fd + 1, &f, (fd_set *) NULL, (fd_set *) NULL, &threeSec); if (sel == 0) { TxError("The %s is responding slowly, or not at all.\n", name); TxError("I'll wait for 20 seconds and then give up.\n"); f = fn; sel = select(fd + 1, &f, (fd_set *) NULL, (fd_set *) NULL, &twentySecs); if (sel == 0) { TxError("The %s did not respond.\n", name); return (char *) NULL; } else if (sel < 0) { if (errno == EINTR) { TxError("Timeout aborted.\n"); } else { perror("magic"); TxError("Error in reading the %s\n", name); } return (char *) NULL; } else TxError("The %s finally responded.\n", name); } else if (sel < 0) { if (errno != EINTR) { perror("magic"); TxError("Error in reading the %s\n", name); return (char *) NULL; } /* else try again, back to top of the loop */ continue; } ch = getc(stream); *newstr = ch; n--; newstr++; if (ch == '\n') break; } *newstr = '\0'; return str; } /*--------------------------------------------------------------------------- * grNullProc -- * * A procedure of the type 'void' that does absolutely nothing. * Used when we need to point a procedure pointer to something, but * don't want it to do anything. * * Results: * None. * * Side Effects: * None. * *---------------------------------------------------------------------------- */ void grNullProc() { }