/* X Window plotting code for Ingrid Jakobsen's reticulate.c program. Allows matrix to displayed on suitable screen. The main function is ShowXPlot, equivalent to WritePostscript in the original program. The other functions break the code into neater chunks and may be useful for other purposes. Written by Hugh Fisher Jan 95. */ #include #include /* exit */ #include #include #include "XPlot.h" /**** Where we're displaying things. ****/ static Display * gDisplay; static Window gWindow; static GC gDrawGC, gWinGC; static Pixmap gBacking; /**** Error reporting ****/ void Fail (String message) { fprintf(stderr, "%s\n", message); exit(-1); } /**** Initialisation and shutdown ****/ Boolean OpenXWindow (String name, int width, int height) { long black, white; int screen; XGCValues values; /* Can we open a display ? */ gDisplay = XOpenDisplay(NULL); if (gDisplay == NULL) return False; /* We're OK. Remember some things */ screen = XDefaultScreen(gDisplay); black = XBlackPixel(gDisplay, screen); white = XWhitePixel(gDisplay, screen); /* Sanity check - but don't abort altogether. Return control to the program */ if (width > XDisplayWidth(gDisplay, screen) || height > XDisplayHeight(gDisplay, screen)) { fprintf(stderr, "Window size requested is bigger than screen\n"); return False; } /* Create a window */ gWindow = XCreateSimpleWindow(gDisplay, DefaultRootWindow(gDisplay), 0, 0, width, height, 1, black, white); if (gWindow == None) Fail("XCreateSimpleWindow"); XStoreName(gDisplay, gWindow, name); /* We accept mouse clicks to end the program and expose events */ XSelectInput(gDisplay, gWindow, ButtonPressMask | ExposureMask); /* And bring it to the front */ XMapRaised(gDisplay, gWindow); /* We draw the points offscreen and use this to update the window as required. Since there are a lot of points but they're only on or off, creating a bitmap saves memory. (Although compared to the 16M genetic data array...still, every bit helps) */ gBacking = XCreatePixmap(gDisplay, gWindow, width, height, 1); if (gBacking == None) Fail("XCreatePixmap"); /* We need separate contexts for updating the window and drawing the points since the window may be deeper */ values.foreground = black; values.background = white; values.function = GXcopy; gWinGC = XCreateGC(gDisplay, gWindow, GCForeground | GCBackground | GCFunction, &values); if (gWinGC == NULL) Fail("XCreateGC - window"); values.foreground = 1; values.background = 0; gDrawGC = XCreateGC(gDisplay, gBacking, GCForeground | GCBackground, &values); if (gDrawGC == NULL) Fail("XCreateGC - offscreen"); /* Clear the window, just to be neat */ XClearWindow(gDisplay, gWindow); /* Clear the offscreen bitmap */ XSetFunction(gDisplay, gDrawGC, GXclear); XFillRectangle(gDisplay, gBacking, gDrawGC, 0, 0, width, height); /* From now on we want to draw normally */ XSetFunction(gDisplay, gDrawGC, GXcopy); /* If we get here, everything has worked. */ return True; } void CloseXWindow () { XFreePixmap(gDisplay, gBacking); XDestroyWindow(gDisplay, gWindow); XCloseDisplay(gDisplay); } /**** Waiting for input and handling screen updates ****/ void WaitMouseClicked () { Boolean done; XEvent event; /* Just sit in event loop until we get a click */ done = False; while (! done) { XNextEvent(gDisplay, &event); switch(event.type) { case ButtonPress: done = True; break; case Expose: XCopyPlane(gDisplay, gBacking, gWindow, gWinGC, event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height, event.xexpose.x, event.xexpose.y, 1); break; /* Compulsory ritual for XLib programs */ case MappingNotify: XRefreshKeyboardMapping((XMappingEvent *)(&event)); break; default: break; } } } /**** At last, the real thing ****/ int ShowXPlot (int numSeq, int seqLen, int matrixSize, int * codons, char ** matrix) { #define kMagic 'm' char name[64]; int row, col, sz = 4; int screen; int i; /* Prompt user for name */ printf("\nName for window > "); fgets(name, sizeof(name), stdin); /* the following two lines remove the and replace it with a null, which looks nicer under eXcursion. 02 Nov 1995 */ for (i = 0; name[i] != '\n' ; i++); name[i] = '\0'; /* Decide how small squares need to be to fit the matrix onto the screen */ gDisplay = XOpenDisplay(NULL); if (gDisplay == NULL) return 1; screen = XDefaultScreen(gDisplay); while ( (matrixSize*sz + 1) > XDisplayHeight(gDisplay, screen)) sz = sz/2; if (sz < 1) sz = 1; /* If we can't open the window, give up and let the main program know. */ if (! OpenXWindow(name, matrixSize*sz, matrixSize*sz)) return 1; /* Now we plot all the points... */ for (row = 0; row < matrixSize; row ++) { for (col = 0; col < matrixSize; col ++) if (matrix[row][col] == kMagic) XFillRectangle(gDisplay, gBacking, gDrawGC, row*sz, col*sz, sz, sz); /* old 1x1 squares no longer used went like this: XDrawPoint(gDisplay, gBacking, gDrawGC, row, col); */ } /* ...and wait for the user to dismiss the window */ WaitMouseClicked(); /* Done */ return 0; #undef kMagic }