ftp.nice.ch/pub/next/games/network/MazeWar.s.tar.gz#/winSunView.c

This is winSunView.c in view mode; [Download] [Up]

/* $Header$ */

/* 
 * window_sunview.c - Window-system specific routines
 * 
 * Author:	Bob Brown
 * 		RIACS
 *	 	NASA Ames Research Center
 * Date:	Thu Dec 5 1986
 * Copyright (c) 1986 Robert L. Brown
 *
 * Revised by:	Malcolm Slaney (@ Schlumberger Palo Alto Research)
 *		August 1987 and January 1988
 *
 */

/* 
 * 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.
 *
 * This file is for Sun 3.1 Sunview.  It has also been tested under Sun 3.4.
 */

/*
 * $Log$
 */

#ifndef	lint
static char rcs_ident[] = "$Header$";
#endif

#include <sys/types.h>			/* I hate programs that do this... */
#include <sys/socket.h>			/* ... but sometimes
you just gotta */
#include <netinet/in.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include <stdio.h>
#include "mazewar.h"

#include <errno.h>

/*
** These constants define where in the main pixwin the subregions lie
*/ 
#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	(mwFontHeight * 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 MAX_X_DIM	MIN_X_DIM
#define	MAX_Y_DIM	(MIN_Y_DIM + SCORE_Y_DIM)

short	mazeBits[MAZEXMAX*MAZEYMAX*16]; /* shorts better be 16 bits! */
Frame	BaseFrame;			/* parent frame */
Canvas	BaseCanvas;			/* Base canvas */
Pixwin	*mwPixwin;			/* parent pixel window */
Pixwin	*viewPixwin;			/* view subwindow */
Pixwin	*mazePixwin;			/* maze subwindow */
Pixwin	*scorePixwin;			/* score subwindow */
struct pixrect *mazePixrect;		/* Pixrect that has the maze */
struct pixrect *ratsPixrect;		/* Pixrect that has the rats */
struct pixfont *mwFont;			/* Font being used */
int	mwFontHeight;			/* Height of the font */
Boolean	inverted = FALSE;		/* user warned of window exit */
int	displayFD;			/* fd of display for events */
int	frameFD;			/* for handling frame events */
int	RastOp = PIX_SRC;
int	MaxOffset;			/* max vertical font offset from 
					 * baseline */
int	flashIcon = FALSE;		/* Should icon be flashing ? */

static short grayBits[16] = {
    0xaaaa, 0x5555, 0xaaaa, 0x5555,
    0xaaaa, 0x5555, 0xaaaa, 0x5555,
    0xaaaa, 0x5555, 0xaaaa, 0x5555,
    0xaaaa, 0x5555, 0xaaaa, 0x5555
};

static short ratBits[] = {
	0x0000,0x0000,0x07C0,0x0FE8,0x0FFC,0x7FFA,0x8FFF,0x8842,
	0x4000,0x3F00,0x0080,0x0100,0x0200,0x0100,0x0000,0x0000
};
mpr_static(ratPixrect, 16, 16, 1, ratBits);

static short deadRatBits[] = {
    0x0000, 0x2088, 0x1045, 0x0082,
    0x0000, 0x1000, 0x2000, 0x4100,
    0x8220, 0x87ff, 0x8ffa, 0x7ffc,
    0x0fe8, 0x07c0, 0x0000, 0x0000
};
mpr_static(deadRatPixrect, 16, 16, 1, deadRatBits);

static short coffeeCupBits[] = {
    0x0080, 0x0700, 0x0800, 0x07c0,
    0x0020, 0x07f0, 0x3c48, 0x47f8,
    0x5808, 0x4008, 0x3c08, 0x0818,
    0x37f6, 0x2002, 0x17fc, 0x0000
};
mpr_static(coffeeCupPixrect, 16, 16, 1, coffeeCupBits);

static short ToolIconBits[] = {
/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16
 */
	0x8888,0x8888,0x8888,0x8888,0x8800,0x0000,0x0000,0x0008,
	0x2200,0x0000,0x0000,0x0022,0x2284,0x0000,0x0820,0x0022,
	0x8884,0x0000,0x0820,0x0008,0x88CC,0x71F1,0xC827,0x1608,
	0x22CC,0x8812,0x2928,0x9922,0x22B4,0x0822,0x2540,0x9022,
	0x88B4,0x7843,0xE547,0x9008,0x8884,0x8882,0x0548,0x9008,
	0x2284,0x8902,0x2288,0x9022,0x2284,0x79F1,0xC287,0x9022,
	0x8800,0x0000,0x0000,0x0008,0x8800,0x0000,0x0000,0x0008,
	0x2200,0x0000,0x0000,0x0022,0x2222,0x2222,0x2222,0x2222,
	0x8888,0x8888,0x8888,0x8888,0x9FFF,0xFFFF,0xFFFF,0xFFFC,
	0x3800,0x0000,0x0000,0x0006,0x3400,0x0000,0x0000,0x0006,
	0x9200,0x0000,0x0000,0x0004,0x9100,0x0000,0x0000,0x0004,
	0x3080,0x0000,0x0000,0x0006,0x3040,0x0000,0x0000,0x01FE,
	0x9020,0x0000,0x0000,0x0304,0x9010,0x0000,0x0000,0x0504,
	0x3008,0x0000,0x0000,0x0906,0x3004,0x0000,0x0000,0x1106,
	0x9002,0x0000,0x0000,0x2104,0x9001,0x0000,0x0000,0x4104,
	0x3000,0x8000,0x0000,0x8106,0x3000,0x4000,0x0001,0x0106,
	0x9000,0x3FFF,0xFFFE,0x0104,0x9000,0x2000,0x0002,0x0104,
	0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106,
	0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104,
	0x3000,0x2000,0x0002,0x0106,0x3000,0x2000,0x0002,0x0106,
	0x9000,0x2000,0x0002,0x0104,0x9000,0x2000,0x0002,0x0104,
	0x3000,0x2000,0x0002,0x0106,0x3000,0x3FFF,0xFFFE,0x0106,
	0x9000,0x4000,0x0001,0x0104,0x9000,0x8000,0x0000,0x8104,
	0x3001,0x0000,0x0000,0x4106,0x3002,0x0000,0x0000,0x2106,
	0x9004,0x0000,0x0000,0x1104,0x9008,0x0001,0xF000,0x0904,
	0x3010,0x000B,0xF800,0x0506,0x3020,0x001F,0xF800,0x0306,
	0x9040,0x002F,0xFF00,0x01FC,0x9080,0x007F,0xF880,0x0004,
	0x3100,0x0021,0x0880,0x0006,0x3200,0x0000,0x0100,0x0006,
	0x9400,0x0000,0x7E00,0x0004,0x9800,0x0000,0x8000,0x0004,
	0x3000,0x0000,0x4000,0x0006,0x3000,0x0000,0x2000,0x0006,
	0x9FFF,0xFFFF,0xFFFF,0xFFFC,0x8888,0x8888,0x8888,0x8888,
	0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222
};
DEFINE_ICON_FROM_IMAGE(ToolIcon, ToolIconBits);

static Cursor	ratCursor, deadRatCursor, hourGlassCursor;

extern char	*getenv();
extern int	errno;

/* state between InitWindow() and StartWindow() */
static char	*progName;

/* 
 * 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;
{
	int i;

	progName = argv[0];

	BaseFrame = window_create(NULL, FRAME, 
		FRAME_ARGC_PTR_ARGV, &argc, argv,
		FRAME_LABEL, "Maze War",
		FRAME_ICON, &ToolIcon,
		0);
	mwFont = (struct pixfont *)window_get(BaseFrame, WIN_FONT);
	mwFontHeight = mwFont->pf_defaultsize.y;
	MaxOffset = 999;
	for(i=0;i<256;i++) {
		if(MaxOffset > mwFont->pf_char[i].pc_home.y)
			MaxOffset = mwFont->pf_char[i].pc_home.y;
	}
/*	printf("maxoffset = %d\n", MaxOffset);				*/
	frameFD = (int)window_get(BaseFrame,  WIN_FD);
}

/* 
 * actually start the display up, after all the user interaction has
 * been done.
 */

StartWindow(ratBits, ratWidth, ratHeight)
short	*ratBits;
{
	int repaintWindow();

	initCursors();

	HourGlassCursor();

	initMaze();
/*	FlipBitmaps();			/* bit-reverse all the bitmaps */
	initRats(ratBits, ratWidth, ratHeight);

	BaseCanvas = window_create(BaseFrame, CANVAS,
		WIN_X, 0,
		WIN_Y, 0,
		WIN_WIDTH, MAX_X_DIM,
		WIN_HEIGHT, MAX_Y_DIM,
		0);
	window_fit(BaseFrame);
	window_set(BaseFrame, WIN_SHOW, TRUE, 0);
	window_set(BaseCanvas,
		   WIN_CONSUME_KBD_EVENTS, WIN_NO_EVENTS, 
		    WIN_ASCII_EVENTS, KBD_USE, KBD_DONE, 0, 
		   WIN_CONSUME_PICK_EVENTS, WIN_NO_EVENTS, WIN_MOUSE_BUTTONS,
		     LOC_WINENTER, LOC_WINEXIT, 0, 
		0);
	mwPixwin = (Pixwin *)window_get(BaseCanvas, CANVAS_PIXWIN);
	notify_dispatch();
	displayFD = (int)window_get(BaseCanvas, WIN_FD);
	viewPixwin = (Pixwin *)pw_region(mwPixwin,
		VIEW_X_ORIGIN, VIEW_Y_ORIGIN, VIEW_X_DIM, VIEW_Y_DIM);
	mazePixwin = (Pixwin *)pw_region(mwPixwin,
		MAZE_X_ORIGIN, MAZE_Y_ORIGIN, MAZE_X_DIM, MAZE_Y_DIM);
	scorePixwin = (Pixwin *)pw_region(mwPixwin,
		SCORE_X_ORIGIN, SCORE_Y_ORIGIN, SCORE_X_DIM, SCORE_Y_DIM);
	window_set(BaseCanvas, 
		CANVAS_REPAINT_PROC, repaintWindow, 
		CANVAS_RESIZE_PROC, repaintWindow,
		CANVAS_RETAINED, TRUE,
		CANVAS_AUTO_CLEAR, TRUE,
		0);
	repaintWindow();
}

/*
 * Shut down the window system, resetting any terminal modes or what
 * have you that may have been altered. No-op for Sun View
 */

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()
{
	pw_writebackground(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
	    RastOp);
}

/*
 * Flash the view window to indicate a hit on an opponent.
 */

FlashTop()
{
	pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
	    PIX_NOT(PIX_SRC), viewPixwin, 0, 0);

	/* might want some delay here */

	pw_rop(viewPixwin, 0, 0, VIEW_X_DIM, VIEW_Y_DIM,
	    PIX_NOT(PIX_SRC), viewPixwin, 0, 0);
}

/*
 * Flash the whole window to indicate we were hit.
 */

FlashScreen()
{
	pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH),
	    window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC),
	    mwPixwin, 0, 0);

	/* might want some delay here */

	pw_rop(mwPixwin, 0, 0, window_get(BaseCanvas, WIN_WIDTH),
	    window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC),
	    mwPixwin, 0, 0);
}

/* 
 * Draw a line in the view subwindow. Don't show it right away if possible.
 */

DrawViewLine(x1, y1, x2, y2)
{
	pw_vector(viewPixwin, x1, y1, x2, y2, RastOp, 1);
}

/* 
 * 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;
	Event	sunEvent;
	struct timeval timeout;
	int	ret;
	static	int	LastWinEnterExit = 0;

    while (1) {
	if (flashIcon == TRUE){
		if (window_get(BaseFrame, FRAME_CLOSED)){
			InvertIcon();
		} else {
			flashIcon = FALSE;
			window_set(BaseFrame, FRAME_ICON, &ToolIcon, 0);
		}
	}

	/* must do this every time, since M.theSocket may change! */
	fdmask = (1 << displayFD) | (1 << frameFD) | (1 << M.theSocket);
	timeout.tv_sec = 0;
	timeout.tv_usec = 250000;
	while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1){
						/* EINTR implies interrupts
						 * which we don't care about.
						 * EBADF implies that things
						 * are probably being shut down
						 * so we should exit.
						 */
		if (errno == EBADF){
			event->eventType = EVENT_INT;
			return;
		}
		if (errno != EINTR)
			MWError("select error on events");
	}
	if (ret == 0) {
		event->eventType = EVENT_TIMEOUT;
		(void) notify_dispatch();
		return;
	}
	if (fdmask & (1 <<displayFD)) {
		window_read_event(BaseCanvas, &sunEvent);
		event->eventType = 0;
		switch (sunEvent.ie_code) {
		case 'a':
			event->eventType = EVENT_A;
			return;

		case 's':
			event->eventType = EVENT_S;
			return;

		case 'd':
			event->eventType = EVENT_D;
			return;

		case 'f':
			event->eventType = EVENT_F;
			return;

		case ' ':
			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 077:
			/* should also deal with Interrupt char */
			event->eventType = EVENT_INT;
			return;

		case MS_RIGHT:
			event->eventType = event_is_down(&sunEvent) ?
				EVENT_RIGHT_D : EVENT_RIGHT_U;
			return;

		case MS_MIDDLE:
			event->eventType = event_is_down(&sunEvent) ?
				EVENT_MIDDLE_D : 0;
			return;

		case MS_LEFT:
			event->eventType = event_is_down(&sunEvent) ?
				EVENT_LEFT_D : EVENT_LEFT_U;
			return;

		case KBD_USE:
#ifdef	DEBUG			
			printf("Have keyboard focus again.....\n");
#endif	DEBUG			
			if (RastOp != PIX_SRC) {
				invertDisplay();
			}
			RastOp = PIX_SRC;
			break;

		case KBD_DONE:
#ifdef	DEBUG			
			printf("Lost keyboard focus.....\n");
#endif	DEBUG			
			if (RastOp != PIX_NOT(PIX_SRC)) {
				invertDisplay();
			}
			RastOp = PIX_NOT(PIX_SRC);
			break;
		case WIN_REPAINT:
			repaintWindow();
			break;
		default:
/*			printf("Window event %d\n", sunEvent.ie_code);	*/
			break;
		}
		continue;
	}
	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);
		ConvertIncoming(event->eventDetail);
		if (cc <= 0) {
			if (cc < 0 && errno != EINTR)
				perror("event recvfrom");
			continue;
		}
		if (fromLen != sizeof(struct sockaddr_in))
			continue;
		return;
	}
	if ( fdmask & (1 << frameFD)) {
		notify_dispatch();
	}
    }
}

/* Please stand by ... */

HourGlassCursor()
{
	window_set(BaseCanvas, WIN_CURSOR, hourGlassCursor, 0);
}

/* Let the games begin! */
RatCursor()
{
	window_set(BaseCanvas, WIN_CURSOR, ratCursor, 0);
}

/* He's dead, Jim ... or might be */
DeadRatCursor()
{
	window_set(BaseCanvas, WIN_CURSOR, deadRatCursor, 0);
}

/* update the displayed bitmap */

mpr_static(Hack_pr, 16, 16, 1, NULL);

HackMazeBitmap(x, y, newBits)
BitCell *newBits;
{
	Hack_pr_data.md_image = newBits->bits;
	pw_rop(mazePixwin, x*16, y*16, 16, 16, RastOp, &Hack_pr, 0, 0);
}

/*
 * 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)
{
	pw_rop(viewPixwin, screenX, screenY, width, height, PIX_SRC^PIX_DST, 
		ratsPixrect, srcX, srcY);
}

/* 
 * 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;
	struct pr_size size;

	pw_text(scorePixwin, 0, (rat+1)*mwFontHeight, RastOp, mwFont, 
		M.ratcb.rats[rat].name);
	sprintf(buf, "%d", (unsigned int)M.ratcb.rats[rat].score);
	size = pf_textwidth(strlen(buf), mwFont, buf);
	leftEdge = SCORE_X_DIM - size.x;
	pw_text(scorePixwin, leftEdge, (rat+1)*mwFontHeight, RastOp, mwFont,
		buf);
}

/* 
 * Clear out the score line for a player that's left the game.
 */

ClearScoreLine(rat)
RatId	rat;
{
	pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, 
		SCORE_X_DIM, mwFontHeight, RastOp);
}

/* 
 * Pretty obvious, eh? Means the guy's in sight.
 */

InvertScoreLine(rat)
RatId	rat;
{
	pw_writebackground(scorePixwin, 0, (rat+1)*mwFontHeight+MaxOffset, 
		SCORE_X_DIM, mwFontHeight, PIX_NOT(PIX_DST));
}

/*
 * END PUBLIC ROUTINES
 */

/* set up needed bitmaps in the server */

initCursors()
{
	ratCursor = cursor_create(CURSOR_IMAGE, &ratPixrect, 
		CURSOR_OP, PIX_SRC^PIX_DST, 
		0);
	deadRatCursor = cursor_create(CURSOR_IMAGE, &deadRatPixrect, 
		CURSOR_OP, PIX_SRC^PIX_DST, 
		0);
	hourGlassCursor = cursor_create(CURSOR_IMAGE, &coffeeCupPixrect, 
		CURSOR_OP, PIX_SRC^PIX_DST, 
		0);
}

/*
 * construct a Pixmap of the maze, and store it in the server.
 */

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;
			}
					
		}
	}
	mazePixrect = mem_point(MAZE_X_DIM, MAZE_Y_DIM, 1, mazeBits);
}

/*
 * actually put the maze Pixmap on the screen
 */

drawMaze()
{
	pw_rop(mazePixwin, 0, 0, MAZE_X_DIM, MAZE_Y_DIM, RastOp, 
		mazePixrect, 0, 0);
}

/* 
 * Create a memory pixrect of the rats so we can do arbitrary
 * bitblts on them later.
 */

initRats(bits, width, height)
short *bits;
{
	ratsPixrect = mem_point(width, height, 1, bits);
}

usage()
{
	fprintf(stderr,"usage: mazewar\n");
	exit(1);
	
}

repaintWindow()
{
#ifdef	DEBUG
	printf("repaint window called\n");
	if (RastOp == PIX_SRC)
		printf("repaintWindow called with RastOp = PIX_SRC.\n");
	else
		printf(
		     "repaintWindow called with RastOp = PIX_NOT(PIX_SRC).\n");
#endif	DEBUG	
	if (RastOp != PIX_SRC)
		pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), 
		       (int)window_get(BaseCanvas, WIN_HEIGHT),
		       PIX_NOT(PIX_CLR), 
		       mwPixwin, 0, 0);
	drawMaze();
	ShowPosition(M.xloc, M.yloc, M.invincible, M.dir);
	ShowView(M.xloc, M.yloc, M.dir);
	ShowAllPositions();

	NewScoreCard();
}
/* 
 * Invert the whole display. Used to let the user know the mouse has
 * strayed outside the window. 
 */

invertDisplay()
{
	pw_rop(mwPixwin, 0, 0, (int)window_get(BaseCanvas, WIN_WIDTH), 
		(int)window_get(BaseCanvas, WIN_HEIGHT), PIX_NOT(PIX_SRC), 
		mwPixwin, 0, 0);
}

/*
* 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 (FALSE);
}

/*
* 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;
}


InvertIcon(){
	Icon	icon;
	Pixrect	*pr;

	icon = (Icon) window_get(BaseFrame, FRAME_ICON);
	pr = (Pixrect *) icon_get(icon, ICON_IMAGE);

	pr_rop(pr, 0, 0, 64, 64, PIX_NOT(PIX_DST), pr, 0, 0);

	icon_set(icon, ICON_IMAGE, pr, 0);
	window_set(BaseFrame, FRAME_ICON, icon, 0);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.