This is winX11.c in view mode; [Download] [Up]
/* $Header: winX11.c,v 1.30 89/02/24 16:29:44 kent Exp $ */ /* * window_X11.c - Window-system specific routines for X11 * * Author: Mike Yang * Western Research Laboratory * Digital Equipment Corporation * Date: Mon Jul 25 1988 */ /*********************************************************** Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts, All Rights Reserved 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 and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Digital not be used in advertising or publicity pertaining to disstribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ******************************************************************/ /* * It is intended that this file presents a window system-independent * set of routines to MazeWar; that is, if you want to run MW under * another window system, this is the only file that needs to be * changed. It isn't yet clear how well I've succeeded, but it's a start. * * Routines that are presented to the outside are capitalized; local * routines are not. */ /*#define USE_BITMAPS /* turn on if you know CopyPlanes works */ /* * $Log: winX11.c,v $ * Revision 1.30 89/02/24 16:29:44 kent * Changed inversion code to use GXxor instead of GXcopyInverted. Makes * the code a little cleaner, and Joel says it'll run slightly * faster (big deal). * * Revision 1.29 89/02/24 16:18:51 kent * Fixed a number of problems with the icon flashing code. * * Revision 1.28 89/02/23 10:10:25 kent * Changed to X11 format bitmaps. * * Revision 1.27 89/02/22 17:28:08 kent * Make the cursor bitmap files internal, instead of trying to read * them at runtime (!). Requires some byteswapping on MSBFirst machines. * * Revision 1.26 89/01/18 17:26:46 kent * Set class hints for the window so the window manager does * the right thing. * * Revision 1.25 88/09/07 10:49:07 kent * Many changes in the name of portability. * * Revision 1.24 88/08/12 11:01:24 kent * Cleaned up image code. * * Revision 1.22 88/08/11 08:48:44 kent * Put Bitmap/CopyPlane code in for those that can use it. * * Revision 1.21 88/08/10 16:41:08 kent * Changed rats to be an XImage that I put. Fixed xor so it works properly * on ANY sex display. * * Revision 1.20 88/08/10 11:16:55 kent * Eliminated use of keycodes in input event mapping. * * Revision 1.19 88/08/09 20:19:33 kent * Changed the mazePixmap to use an XImage and always put the bits * remotely. Amazingly enough, the performance is a lot better, and * the startup delay is a lot less. * * Revision 1.18 88/08/09 19:42:32 kent * Sped up arrow display code (HackMazeBitmap). Previously was creating * a Pixmap (and not destroying it!) every time -- costing a round trip * for each call. Changed it to Create/Put/Destroy an XImage, which * costs a little locally, but no round trips. Big difference! * * Also some general code cleanup. * * Revision 1.17 88/07/25 18:18:27 kent * Switch to zero-width lines. Much faster. * * Revision 1.16 88/07/25 09:12:40 mikey * cleanup source * * Revision 1.15 88/07/25 09:01:54 mikey * Coalesced line drawing requests, fixed depth bugs * * Revision 1.14 88/07/20 11:53:26 mikey * moved code from StartWindow to InitWindow so as to eliminate timeout * problems with ratDoctor. * * Revision 1.13 88/06/21 09:24:51 mikey * Fixed some bugs in the previous version. FocusIn doesn't * do anything now if an Expose event is in the queue at all. * * Revision 1.12 88/06/20 16:52:35 mikey * Use XCheckIfEvent to reduce duplication if focusin and expose events * follow each other, eliminated use of GXcopyInverted and instead * set foreground and background, tried to eliminate buttonpress * effect when selecting window. * * Revision 1.11 88/06/20 10:01:06 mikey * Inverts display when input focus is not in the window. A lot of * updating... maybe it can be reduced. * * Revision 1.10 88/06/19 15:16:18 mikey * Handles 32x32 bitmap for X11 and eliminated kludges for wm. * Currently flashes icon depending on input focus. Should * change to depending on open/closed. * * Revision 1.9 88/06/17 14:53:12 mikey * Flashing icon on focus events * * Revision 1.8 88/06/17 12:48:52 mikey * Icon fixed for color (gpx) displays. * * Revision 1.7 88/06/17 11:35:41 mikey * fixed inverted bitmaps on vs100, eliminated blob, created icon * for monochrome wm. icon still messed for gpx. * * Revision 1.6 88/06/17 10:47:31 mikey * undid invertDisplay because of problems with screen saver and with * window exposure/update. other problems: blob in upperleft of\ * maze on vs100, inverted bitmaps on vs100, unsuccessful creation * of 32x32 icon [oxmap. * * Revision 1.5 88/06/16 16:09:30 mikey * replaced most uses of XCreateBitmap with XCreatePixmapFromBitmapData * to solve vs100 problems. still have negated-black/white problems * with bitmaps and vs100. * * Revision 1.4 88/06/16 15:29:55 mikey * disabled icon flashing, fixed inverting problems, still have to * fix vs100 bitmap display * * Revision 1.3 88/06/15 11:40:05 mikey * before trying to fix icon window * */ #ifndef lint static char rcs_ident[] = "$Header: winX11.c,v 1.30 89/02/24 16:29:44 kent Exp $"; #endif #include <X11/Xos.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <X11/Xresource.h> #include <X11/StringDefs.h> #include <sys/types.h> #include <sys/time.h> #include <netinet/in.h> #include <errno.h> #include <pwd.h> #include <stdio.h> #include <strings.h> #include "mazewar.h" #undef Boolean #include <X11/Intrinsic.h> #define VIEW_X_DIM 400 #define VIEW_Y_DIM 400 #define VIEW_X_ORIGIN 100 #define VIEW_Y_ORIGIN 50 #define MAZE_X_DIM (MAZEXMAX*16) #define MAZE_Y_DIM (MAZEYMAX*16) #define MAZE_X_ORIGIN 48 #define MAZE_Y_ORIGIN 451 #define SCORE_X_DIM 192 #define SCORE_Y_DIM ((scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent) * MAXRATS) #define SCORE_X_ORIGIN 208 #define SCORE_Y_ORIGIN 708 #define MIN_X_DIM 608 /* see comments for InitWindow() */ #define MIN_Y_DIM SCORE_Y_ORIGIN /* see InitWindow() */ #define DEFAULT_FONT "8x13" #define DEFAULT_POSITION "%dx%d+0+0" /* upper left hand corner */ #define ICON_FLASH_PERIOD 4 short mazeBits[MAZEXMAX*MAZEYMAX*16]; /* shorts better be 16 bits! */ Window mwWindow; /* parent window */ #ifdef USE_BITMAPS Pixmap mazeBitmap; /* the maze */ Pixmap ratsBitmap; /* the rats */ #else XImage *ratsImage; /* the rats */ XImage *mazeImage; /* the maze */ #endif USE_BITMAPS Pixmap iconMask; /* mask for icon outline */ XFontStruct *scoreFontInfo; Boolean mapped = FALSE; /* should really display? */ Boolean flashIcon = FALSE; /* should icon be flashing? */ Boolean iconInverted = FALSE; /* icon should be/is inverted */ int displayFD; /* fd of display for events */ Pixel fg_pixel; /* color of lines and such */ Pixel bg_pixel; /* color of background */ Pixel mouseground; /* mouse cursor color */ Font scoreFont; /* font for printing scores */ Pixel borderColor; Cardinal borderWidth; Display *dpy; /* display used */ int screen; /* screen on the display */ unsigned int cur_width, cur_height; /* current width, height of window */ GC copyGC, xorGC; /* graphics contexts for window */ Pixmap icon_pixmap, iconmask_pixmap; /* icon, mask bitmaps */ Pixmap icon_reverse_pixmap; int icon_flash = 0; XImage *arrowImage; #include "bitmaps/icon.ic" #include "bitmaps/rat.cur" #include "bitmaps/ratMask.cur" #include "bitmaps/dRat.cur" #include "bitmaps/dRatMask.cur" #include "bitmaps/cup.cur" static Cursor ratCursor, deadRatCursor, hourGlassCursor; extern char *getenv(); extern int errno; static char *progName; Pixmap xCreateBitmapFromBitCell(); static XrmOptionDescRec opTable[] = { {"-mouse", "*mouseColor", XrmoptionSepArg, (caddr_t) NULL}, }; #define XtNmouse "mouse" int zero = 0; int one = 1; static XtResource resources[] = { {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), (Cardinal)&fg_pixel, XtRString, "black"}, {XtNbackground, XtCBackground, XtRPixel, sizeof(Pixel), (Cardinal)&bg_pixel, XtRString, "white"}, {XtNmouse, XtCCursor, XtRPixel, sizeof(Pixel), (Cardinal)&mouseground, XtRString, "black"}, {XtNfont, XtCFont, XtRFont, sizeof(Font), (Cardinal)&scoreFont, XtRString, DEFAULT_FONT}, {XtNborderWidth, XtCBorderWidth, XtRInt, sizeof(int), (Cardinal)&borderWidth, XtRInt, (caddr_t) &one}, {XtNborder, XtCBorderColor, XtRPixel, sizeof(Pixel), (Cardinal)&borderColor, XtRString, "black"}, }; /* * ALL COORDINATES ASSUME ORIGIN (0,0) AT UPPER LEFT! */ /* * Initialize the window. The overall window must be at least 608x by * 808y (the size of the Alto screen). There are three distinct * subregions: * A 400x by 400y area for the view, beginning at (100,50) * A 512x by 256y area for the maze, beginning at (48, 451) * A 192x by 96y area for the score lines, at (208, 706) * * Actually, the y dimension of both the whole window and the score * subwindow must be enough to accommodate MAXRATS lines of the * height of the scoreFont. */ /* parse arguments and set up window state */ InitWindow(argc, argv) char **argv; { XGCValues gc_values; XWMHints wmhints; Widget w; XClassHint classHint; GC iconGC; progName = rindex(argv[0], '/'); if (progName) progName++; else progName = argv[0]; /* * We cheat here by using the Toolkit to do the initialization work. * We just ignore the top-level widget that gets created. */ w = XtInitialize("mazewar", "mazewar", opTable, XtNumber(opTable), &argc, argv); dpy = XtDisplay(w); screen = DefaultScreen(dpy); XtGetApplicationResources(w, (caddr_t) NULL, resources, XtNumber(resources), NULL, (Cardinal) 0); if (!scoreFont) MWError("cannot open font"); scoreFontInfo = XQueryFont(dpy, scoreFont); cur_width = MIN_X_DIM; cur_height = MIN_Y_DIM + (MAXRATS+1) * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent); mwWindow = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 0, 0, cur_width, cur_height, borderWidth, 0, bg_pixel); XStoreName(dpy, mwWindow, "MazeWar"); XSetIconName(dpy, mwWindow, "MazeWar"); classHint.res_name = "mazewar"; classHint.res_class = "mazewar"; XSetClassHint(dpy, mwWindow, &classHint); gc_values.function = GXcopy; gc_values.foreground = fg_pixel; gc_values.background = bg_pixel; gc_values.font = scoreFont; gc_values.line_width = 0; copyGC = XCreateGC(dpy, mwWindow, GCFunction | GCForeground | GCBackground | GCLineWidth | GCFont, &gc_values); gc_values.function = GXxor; gc_values.plane_mask = AllPlanes; gc_values.foreground = fg_pixel ^ bg_pixel; gc_values.background = 0; xorGC = XCreateGC(dpy, mwWindow, GCFunction | GCForeground | GCBackground | GCPlaneMask, &gc_values); icon_pixmap = XCreatePixmapFromBitmapData( dpy, mwWindow, icon_bits, icon_width, icon_height, fg_pixel, bg_pixel, XDefaultDepth(dpy, screen)); /* is this even used? */ gc_values.function = GXclear; gc_values.plane_mask = AllPlanes; iconGC = XCreateGC(dpy, mwWindow, GCFunction | GCPlaneMask, &gc_values); iconmask_pixmap = XCreatePixmap(dpy, mwWindow, icon_width, icon_height, XDefaultDepth(dpy, screen)); XFillRectangle(dpy, iconmask_pixmap, iconGC, icon_width, icon_height); icon_reverse_pixmap = XCreatePixmapFromBitmapData(dpy, mwWindow, icon_bits, icon_width, icon_height, bg_pixel, fg_pixel, XDefaultDepth(dpy, screen)); wmhints.flags = IconPixmapHint | IconMaskHint; wmhints.icon_pixmap = icon_pixmap; wmhints.icon_mask = iconmask_pixmap; XSetWMHints(dpy, mwWindow, &wmhints); initCursors(); arrowImage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, NULL, 16, 16, 8, 2); arrowImage->byte_order = MSBFirst; arrowImage->bitmap_bit_order = MSBFirst; } /* * actually start the display up, after all the user interaction has * been done. */ StartWindow(ratBits, ratWidth, ratHeight) short *ratBits; { XSelectInput(dpy, mwWindow, KeyPressMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | StructureNotifyMask | FocusChangeMask); HourGlassCursor(); initMaze(); SwapBitmaps(); displayFD = XConnectionNumber(dpy); XMapWindow(dpy, mwWindow); /* Map window to screen */ initRats(ratBits, ratWidth, ratHeight); } /* * Shut down the window system, resetting any terminal modes or what * have you that may have been altered. No-op for X11. */ StopWindow() { } /* * Clear out the view subwindow. If possible, delay the visible effect * until all the lines have been drawn (since this is only called by * ShowView(), which is about to draw a bunch of lines). */ ClearView() { XClearArea(dpy, mwWindow, VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM, False); } /* * Flash the view window to indicate a hit on an opponent. */ FlashTop() { XFillRectangle(dpy, mwWindow, xorGC, VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM); XFlush(dpy); /* might want some delay here */ XFillRectangle(dpy, mwWindow, xorGC, VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM); XFlush(dpy); } /* * Flash the whole window to indicate we were hit. */ FlashScreen() { XFillRectangle(dpy, mwWindow, xorGC, 0, 0, cur_width, cur_height); XFlush(dpy); /* might want some delay here */ XFillRectangle(dpy, mwWindow, xorGC, 0, 0, cur_width, cur_height); XFlush(dpy); } /* * Draw a line in the view subwindow. Don't show it right away if possible. */ DrawViewLine(x1, y1, x2, y2) { XDrawLine(dpy, mwWindow, copyGC, x1+VIEW_X_ORIGIN, y1+VIEW_Y_ORIGIN, x2+VIEW_X_ORIGIN, y2+VIEW_Y_ORIGIN); } /* * Event handling. Presents a uniform event interface to the game, and * handles all other events in here. The game only sees the events * that affect it directly, as defined in mazewar.h. They are: * * keypresses that affect the game * mouse button clicks * incoming network packets * timeouts (there's a "heartbeat" to drive the shot clock) * * All other events should be swallowed by this routine. Also, since * keyboard focus is dependent on the mouse being in the game window, * try to let the user know that he's wandered outside the window * by inverting the window (should make it obvious) and is now vulnerable * and defenseless. */ void NextEvent(event) MWEvent *event; { int fdmask; XEvent xev; struct timeval timeout; int ret; char c; while (1) { icon_flash = (++icon_flash) % ICON_FLASH_PERIOD; if (!XPending(dpy)) /* this does an XFlush, too */ if (flashIcon && !icon_flash && !mapped) { /* invert the icon */ iconInverted = !iconInverted; repaintIcon(); } /* * Look for events. Try to arrange that X events have priority over * network traffic. See if there's an X event pending. If so, check * for a net event, too; if not, select on both the network and the X * connection. If that doesn't time out, but there's no X event * pending, try again, just selecting on the X connection. If that * times out, let the network event get processed. * * Can't just select on the two fds, because there may be X events * pending in the queue that have already been read. * * This may look baroque, but we've seen some instances where X server * latency seems to let the network events take priority over sever * events, leading to sluggish keyboard response and lots of local * death. * * Also, can't just ignore network events -- if the server is slow and * lots of X events get queued, someone else's ratDoctor will time you * out if you never answer. */ if (!XPending(dpy)) { fdmask = (1 << displayFD) | (1 << M.theSocket); timeout.tv_sec = 0; timeout.tv_usec = 500000; while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1) if (errno != EINTR) MWError("select error on events"); if (ret == 0) { event->eventType = EVENT_TIMEOUT; return; } } else { fdmask = 1 << M.theSocket; timeout.tv_sec = 0; timeout.tv_usec = 0; while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1) if (errno != EINTR) MWError("select error on events"); } if (XPending(dpy)) { XNextEvent(dpy, &xev); switch (xev.type) { case KeyPress: event->eventType = 0; XLookupString((XKeyEvent *) &xev, &c, 1, NULL, NULL); switch(c) { case 'a': case '4': /* keypad */ event->eventType = EVENT_A; return; case 's': case '5': event->eventType = EVENT_S; return; case 'd': case '6': event->eventType = EVENT_D; return; case 'f': case ',': event->eventType = EVENT_F; return; case ' ': case '\033': /* ESC lead in of arrow */ event->eventType = EVENT_BAR; return; case 'i': event->eventType = EVENT_I; return; case 'k': event->eventType = EVENT_K; return; case 'o': event->eventType = EVENT_O; return; case 'l': event->eventType = EVENT_L; return; case 'q': case '\177': /* DEL */ case '\003': /* ^C */ event->eventType = EVENT_INT; return; } break; #define RightButton Button3 #define MiddleButton Button2 #define LeftButton Button1 case ButtonPress: event->eventType = 0; switch(((XButtonPressedEvent *) &xev)->button & 0xff) { case RightButton: event->eventType = EVENT_RIGHT_D; return; case MiddleButton: event->eventType = EVENT_MIDDLE_D; return; case LeftButton: event->eventType = EVENT_LEFT_D; return; } break; case ButtonRelease: event->eventType = 0; switch(((XButtonReleasedEvent *) &xev)->button&0xff) { case RightButton: event->eventType = EVENT_RIGHT_U; return; case LeftButton: event->eventType = EVENT_LEFT_U; return; } break; case Expose: repaintWindow(); break; case FocusIn: case MapNotify: mapped = TRUE; iconInverted = FALSE; flashIcon = FALSE; repaintIcon(); break; case FocusOut: case UnmapNotify: mapped = FALSE; break; } } if (fdmask & (1 << M.theSocket)) { int fromLen = sizeof(event->eventSource); int cc; event->eventType = EVENT_NETWORK; cc = recvfrom(M.theSocket, event->eventDetail, sizeof(RatPacket), 0, &event->eventSource, &fromLen); if (cc <= 0) { if (cc < 0 && errno != EINTR) perror("event recvfrom"); continue; } if (fromLen != sizeof(struct sockaddr_in)) continue; ConvertIncoming(event->eventDetail); return; } } } /* * Peek to see if there's a keyboard event waiting, in case the * program wants to short-circuit some code. If your system won't let * you implement this feature easily, just always return FALSE. */ Boolean KBEventPending() { return (XPending(dpy) != 0); } /* Please stand by ... */ HourGlassCursor() { XDefineCursor(dpy, mwWindow, hourGlassCursor); XFlush(dpy); } /* Let the games begin! */ RatCursor() { XDefineCursor(dpy, mwWindow, ratCursor); XFlush(dpy); } /* He's dead, Jim ... or might be */ DeadRatCursor() { XDefineCursor(dpy, mwWindow, deadRatCursor); XFlush(dpy); } /* * Update the displayed bitmap. Would really like to store the arrow bitmaps * remotely, but the non-normal ones (especially otherArrows) may change. */ HackMazeBitmap(x, y, newBits) BitCell *newBits; { arrowImage->data = (char *)newBits; XPutImage(dpy, mwWindow, copyGC, arrowImage, 0, 0, x*16 + MAZE_X_ORIGIN, y*16 + MAZE_Y_ORIGIN, 16, 16); } /* * Display a rat. Width, height, srcX and srcY describe the subbitmap in the * rats bitmap that is the desired view of the opponent. */ DisplayRatBitmap(screenX, screenY, width, height, srcX, srcY) { #ifdef USE_BITMAPS XCopyPlane(dpy, ratsBitmap, mwWindow, xorGC, srcX, srcY, width, height, screenX+VIEW_X_ORIGIN, screenY+VIEW_Y_ORIGIN, 1); #else XPutImage(dpy, mwWindow, xorGC, ratsImage, srcX, srcY, screenX+VIEW_X_ORIGIN, screenY+VIEW_Y_ORIGIN, width, height); #endif USE_BITMAPS } /* * Display the score line for the indicated player. Name is left * justified, score is right justified within the score window. */ WriteScoreString(rat) RatId rat; { char buf[64]; int leftEdge; sprintf(buf, "%d", (unsigned int) M.ratcb.rats[rat].score); XClearArea(dpy, mwWindow, SCORE_X_ORIGIN, SCORE_Y_ORIGIN + rat * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent), SCORE_X_DIM, (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent), FALSE); XDrawImageString(dpy, mwWindow, copyGC, SCORE_X_ORIGIN, SCORE_Y_ORIGIN + rat * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent) + scoreFontInfo->max_bounds.ascent, M.ratcb.rats[rat].name, strlen(M.ratcb.rats[rat].name)); leftEdge = SCORE_X_DIM - XTextWidth(scoreFontInfo, buf, strlen(buf)); XDrawImageString(dpy, mwWindow, copyGC, leftEdge+SCORE_X_ORIGIN, SCORE_Y_ORIGIN + rat * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent) + scoreFontInfo->max_bounds.ascent, buf, strlen(buf)); } /* * Clear out the score line for a player that's left the game. */ ClearScoreLine(rat) RatId rat; { XClearArea(dpy, mwWindow, SCORE_X_ORIGIN, SCORE_Y_ORIGIN + rat * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent), SCORE_X_DIM, scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent, False); } /* * Pretty obvious, eh? Means the guy's in sight. */ InvertScoreLine(rat) RatId rat; { XFillRectangle(dpy, mwWindow, xorGC, SCORE_X_ORIGIN, SCORE_Y_ORIGIN + rat * (scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent), SCORE_X_DIM, scoreFontInfo->max_bounds.ascent + scoreFontInfo->max_bounds.descent); } /* * Let the user know that a new player joined. This really should only * take effect if the window is iconic, so you can keep a game around * all day, close it up when there's no activity, and know when * someone else is also out to kill some time. */ NotifyPlayer() { flashIcon = TRUE; } /* * END PUBLIC ROUTINES */ /* set up needed bitmaps in the server */ initCursors() { Pixmap p, m; XColor mc, bc; mc.pixel = mouseground; bc.pixel = bg_pixel; mc.flags = DoRed | DoGreen | DoBlue; bc.flags = DoRed | DoGreen | DoBlue; XQueryColor(dpy, DefaultColormap(dpy, screen), &mc); XQueryColor(dpy, DefaultColormap(dpy, screen), &bc); m = XCreateBitmapFromData(dpy, mwWindow, (char *)ratMask_bits, ratMask_width, ratMask_height); p = XCreateBitmapFromData(dpy, mwWindow, (char *)rat_bits, rat_width, rat_height); ratCursor = XCreatePixmapCursor(dpy, p, m, &mc, &bc, rat_x_hot, rat_y_hot); m = XCreateBitmapFromData(dpy, mwWindow, (char *)dRatMask_bits, dRatMask_width, dRatMask_height); p = XCreateBitmapFromData(dpy, mwWindow, (char *)dRat_bits, dRat_width, dRat_height); deadRatCursor = XCreatePixmapCursor(dpy, p, m, &mc, &bc, 0, 0); p = XCreateBitmapFromData(dpy, mwWindow, (char *)cup_bits, cup_width, cup_height); hourGlassCursor = XCreatePixmapCursor(dpy, p, p, &mc, &bc, 0, 0); } /* * construct an XImage of the maze. */ initMaze() { register int i, j, k, line, index; for (i = 0; i < MAZEYMAX; i++) { line = i * MAZEXMAX * MAZEYMAX; for (j = 0; j < MAZEXMAX; j++) { index = line + j; for (k = 0; k < 16; k++) { if (M.maze[j].y[i]) mazeBits[index] = 0177777; else mazeBits[index] = 0; index += 32; } } } #ifdef USE_BITMAPS mazeBitmap = xCreateBitmapFromBitCell(dpy, mwWindow, (char *) mazeBits, MAZE_X_DIM, MAZE_Y_DIM); if (mazeBitmap == 0) #else mazeImage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, mazeBits, MAZE_X_DIM, MAZE_Y_DIM, 8, MAZE_X_DIM>>3); mazeImage->byte_order = MSBFirst; mazeImage->bitmap_bit_order = MSBFirst; if (mazeImage == 0) #endif USE_BITMAPS MWError("Can't create maze Pixmap"); } /* * actually put the maze Pixmap on the screen. */ drawMaze() { #ifdef USE_BITMAPS XCopyPlane(dpy, mazeBitmap, mwWindow, copyGC, 0, 0, MAZE_X_DIM, MAZE_Y_DIM, MAZE_X_ORIGIN, MAZE_Y_ORIGIN, 1); #else XPutImage(dpy, mwWindow, copyGC, mazeImage, 0, 0, MAZE_X_ORIGIN, MAZE_Y_ORIGIN, MAZE_X_DIM, MAZE_Y_DIM); #endif USE_BITMAPS } /* * Create the bitmap of the rats for later use. */ initRats(bits, width, height) short *bits; { #ifdef USE_BITMAPS ratsBitmap = xCreateBitmapFromBitCell(dpy, mwWindow, (char *) bits, width, height); if (ratsBitmap == 0) #else ratsImage = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, (char *) bits, width, height, 8, width>>3); ratsImage->byte_order = MSBFirst; ratsImage->bitmap_bit_order = MSBFirst; if (ratsImage == 0) #endif USE_BITMAPS MWError("Can't create rats"); } /* * Repaint the window for exposure and resize events. All drawing is * done here, even though there are times during the initialization * code when it would seem obvious to put some of the display up; this * way portions of the display aren't shown twice then. */ static repaintWindow() { drawMaze(); ShowPosition(M.xloc, M.yloc, M.invincible, M.dir); ShowView(M.xloc, M.yloc, M.dir); ShowAllPositions(); NewScoreCard(); XFlush(dpy); } /* * Repaint the icon for exposure events, or while flashing to indicate * that there's a new player. */ static repaintIcon() { XWMHints wmhints; if (!iconInverted) wmhints.icon_pixmap = icon_pixmap; else wmhints.icon_pixmap = icon_reverse_pixmap; wmhints.flags = IconPixmapHint | IconMaskHint; wmhints.icon_mask = iconmask_pixmap; XSetWMHints(dpy, mwWindow, &wmhints); } /* * Invert the whole display. Used to let the user know the mouse has * strayed outside the window. We don't do this for X11. */ static invertDisplay() { } /* * A hack of XCreateBitmapFromData that assumes MSBFirst BitCells insterad of * LSBFirst bytes. */ Pixmap xCreateBitmapFromBitCell(display, d, data, width, height) Display *display; Drawable d; char *data; unsigned int width, height; { XImage ximage; GC gc; Pixmap pix; pix = XCreatePixmap(display, d, width, height, 1); if (!pix) return(0); gc = XCreateGC(display, pix, (unsigned long)0, (XGCValues *)0); ximage.height = height; ximage.width = width; ximage.depth = 1; ximage.xoffset = 0; ximage.format = ZPixmap; ximage.data = data; ximage.byte_order = MSBFirst; ximage.bitmap_unit = 8; ximage.bitmap_bit_order = MSBFirst; ximage.bitmap_pad = 8; ximage.bytes_per_line = (width+7)/8; XPutImage(display, pix, gc, &ximage, 0, 0, 0, 0, width, height); XFreeGC(display, gc); return(pix); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.