#include <MacHeaders.h>#include <Timer.h>#include <profiler.h>#include "sq.h"/*** Compilation Options:**	define PLUGIN		to compile code for Netscape Plug-in*	define MAKE_PROFILE	to compile code for profiling*	define SHLIB		to compile code for a shared library****///#define PLUGIN//#define MAKE_PROFILE//#define SHLIB/*** Enumerations ***/enum { appleID = 1, fileID, editID };enum { quitItem = 1 };/*** Variables -- Imported from Virtual Machine ***/extern unsigned char *memory;extern int interruptKeycode;extern int interruptPending;extern int interruptCheckCounter;extern int savedWindowSize;  /* set from header when image file is loaded *//*** Variables -- image and path names ***/#define IMAGE_NAME_SIZE 300char imageName[IMAGE_NAME_SIZE + 1];  /* full path to image */#define SHORTIMAGE_NAME_SIZE 40char shortImageName[SHORTIMAGE_NAME_SIZE + 1];  /* just the file name, reported on launch */#define VMPATH_SIZE 300char vmPath[VMPATH_SIZE + 1];  /* full path to interpreter's directory *//*** Variables -- Mac Related ***/MenuHandle		appleMenu = nil;Handle			clipboardBuffer = nil;MenuHandle		editMenu = nil;MenuHandle		fileMenu = nil;CTabHandle		stColorTable = nil;PixMapHandle	stPixMap = nil;WindowPtr		stWindow = nil;#ifdef SHLIBFSSpec			appSpec;#endif/*** Variables -- Event Recording ***/#define KEYBUF_SIZE 64int keyBuf[KEYBUF_SIZE];	/* circular buffer */int keyBufGet = 0;			/* index of next item of keyBuf to read */int keyBufPut = 0;			/* index of next item of keyBuf to write */int keyBufOverflows = 0;	/* number of characters dropped */int buttonState = 0;		/* mouse button and modifier state when mouse							   button went down or 0 if not pressed */Point savedMousePosition;	/* mouse position when window is inactive */int windowActive = true;	/* true if the Squeak window is the active window *//* This table maps the 5 Macintosh modifier key bits to 4 Squeak modifier   bits. (The Mac shift and caps lock keys are both mapped to the single   Squeak shift bit).		Mac bits: <control><option><caps lock><shift><command>		ST bits:  <command><option><control><shift>   */ char modifierMap[32] = {	0,  8, 1,  9, 1,  9, 1,  9, 4, 12, 5, 13, 5, 13, 5, 13,	2, 10, 3, 11, 3, 11, 3, 11, 6, 14, 7, 15, 7, 15, 7, 15};/*** Functions ***/void AdjustMenus(void);void FreeClipboard(void);void FreePixmap(void);int  HandleEvents(void);void HandleMenu(int mSelect);void HandleMouseDown(EventRecord *theEvent);void InitMacintosh(void);void InstallAppleEventHandlers(void);void RecordFullPathForImageName(char *localImageName);void SetColorEntry(int index, int red, int green, int blue);void SetUpClipboard(void);void SetUpMenus(void);void SetUpPixmap(void);void SetUpWindow(void);/* event capture */int recordKeystroke(EventRecord *theEvent);int recordModifierButtons(EventRecord *theEvent);int recordMouseDown(EventRecord *theEvent);/*** Apple Event Handlers ***/static pascal OSErr HandleOpenAppEvent(AEDescList *aevt, AEDescList *reply, int refCon);static pascal OSErr HandleOpenDocEvent(AEDescList *aevt, AEDescList *reply, int refCon);static pascal OSErr HandlePrintDocEvent(AEDescList *aevt, AEDescList *reply, int refCon);static pascal OSErr HandleQuitAppEvent(AEDescList *aevt, AEDescList *reply, int refCon);/*** Apple Event Handling ***/void InstallAppleEventHandlers() {	OSErr	err;	long	result;	shortImageName[0] = 0;	err = Gestalt(gestaltAppleEventsAttr, &result);	if (err == noErr) {			AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc(HandleOpenAppEvent),  0, false);		AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,   NewAEEventHandlerProc(HandleOpenDocEvent),  0, false);		AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments,  NewAEEventHandlerProc(HandlePrintDocEvent), 0, false);		AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(HandleQuitAppEvent),  0, false);	}}pascal OSErr HandleOpenAppEvent(AEDescList *aevt, AEDescList *reply, int refCon) {	/* User double-clicked application; look for "clone.image" in same directory */	/* record path to VM's home folder */	dir_PathToWorkingDir(vmPath, VMPATH_SIZE);	/* use default image name in same directory as the VM */	strcpy(shortImageName, "clone.image");	return noErr;}pascal OSErr HandleOpenDocEvent(AEDescList *aevt, AEDescList *reply, int refCon) {	/* User double-clicked an image file. Record the path to the VM's directory,	   then set the default directory to the folder containing the image and	   record the image name. Fail if mullitple image files were selected. */	OSErr		err;	AEDesc		fileList = {'NULL', NULL};	long		numFiles, size;	DescType	type;	AEKeyword	keyword;	FSSpec		fileSpec;	WDPBRec		pb;	/* record path to VM's home folder */	dir_PathToWorkingDir(vmPath, VMPATH_SIZE);	/* copy document list */	err = AEGetKeyDesc(aevt, keyDirectObject, typeAEList, &fileList);	if (err) goto done;	/* count list elements */	err = AECountItems( &fileList, &numFiles);	if (err) goto done;	if (numFiles != 1) {		error("You may only open one Squeak image file at a time.");	}	/* get image name */	err = AEGetNthPtr(&fileList, 1, typeFSS,					  &keyword, &type, (Ptr) &fileSpec, sizeof(fileSpec), &size);	if (err) goto done;	strcpy(shortImageName, p2cstr(fileSpec.name));	/* make image directory the default */	pb.ioNamePtr = NULL;	pb.ioVRefNum = fileSpec.vRefNum;	pb.ioWDDirID = fileSpec.parID;	PBHSetVolSync(&pb);done:	AEDisposeDesc(&fileList);	return err;}pascal OSErr HandlePrintDocEvent(AEDescList *aevt, AEDescList *reply, int refCon) {	return errAEEventNotHandled;}pascal OSErr HandleQuitAppEvent(AEDescList *aevt, AEDescList *reply, int refCon) {	return errAEEventNotHandled;}/*** VM Home Directory Path ***/int vmPathSize(void) {	return strlen(vmPath);}int vmPathGetLength(int sqVMPathIndex, int length) {	char *stVMPath = (char *) sqVMPathIndex;	int count, i;	count = strlen(vmPath);	count = (length < count) ? length : count;	/* copy the file name into the Squeak string */	for (i = 0; i < count; i++) {		stVMPath[i] = vmPath[i];	}	return count;}/*** Mac-related Functions ***/void AdjustMenus(void) {	WindowPeek		wp;	int				isDeskAccessory;	wp = (WindowPeek) FrontWindow();	if (wp != NULL) {		isDeskAccessory = (wp->windowKind < 0);	} else {		isDeskAccessory = false;	}	if (isDeskAccessory) {		/* Enable items in the Edit menu */		EnableItem(editMenu, 1);		EnableItem(editMenu, 3);		EnableItem(editMenu, 4);		EnableItem(editMenu, 5);		EnableItem(editMenu, 6);	} else {		/* Disable items in the Edit menu */		DisableItem(editMenu, 1);		DisableItem(editMenu, 3);		DisableItem(editMenu, 4);		DisableItem(editMenu, 5);		DisableItem(editMenu, 6);	}}int HandleEvents(void) {	EventRecord		theEvent;	int				ok;	ok = GetNextEvent(everyEvent, &theEvent);	if (ok) {		switch (theEvent.what) {			case mouseDown:				HandleMouseDown(&theEvent);				return false;			break;			case mouseUp:				recordModifierButtons(&theEvent);				return false;			break;			case keyDown:			case autoKey:				if ((theEvent.modifiers & cmdKey) != 0) {					AdjustMenus();					HandleMenu(MenuKey(theEvent.message & charCodeMask));				}				recordModifierButtons(&theEvent);				recordKeystroke(&theEvent);			break;			case updateEvt:				BeginUpdate(stWindow);				fullDisplayUpdate();  /* this makes VM call ioShowDisplay */				EndUpdate(stWindow);			break;			case activateEvt:				if (theEvent.modifiers & activeFlag) {					windowActive = true;				} else {					GetMouse(&savedMousePosition);					windowActive = false;				}				InvalRect(&stWindow->portRect);			break;			case kHighLevelEvent:				AEProcessAppleEvent(&theEvent);			break;		}	}	return ok;}void HandleMenu(int mSelect) {	int			menuID, menuItem;	Str255		name;	GrafPtr		savePort;	menuID = HiWord(mSelect);	menuItem = LoWord(mSelect);	switch (menuID) {		case appleID:			GetPort(&savePort);			GetItem(appleMenu, menuItem, name);			OpenDeskAcc(name);			SetPort(savePort);		break;		case fileID:			if (menuItem == quitItem) {				exit(-1);			}		break;		case editID:			if (!SystemEdit(menuItem - 1)) {				SysBeep(5);			}		break;	}}void HandleMouseDown(EventRecord *theEvent) {	WindowPtr	theWindow;	Rect		growLimits = { 20, 20, 4000, 4000 };	Rect		dragBounds;	int			windowCode, newSize;	windowCode = FindWindow(theEvent->where, &theWindow);	switch (windowCode) {		case inSysWindow:			SystemClick(theEvent, theWindow);		break;		case inMenuBar:			AdjustMenus();			HandleMenu(MenuSelect(theEvent->where));		break;		case inDrag:			dragBounds = qd.screenBits.bounds;			if (theWindow == stWindow) {				DragWindow(stWindow, theEvent->where, &dragBounds);			}		break;		case inGrow:			if (theWindow == stWindow) {				newSize = GrowWindow(stWindow, theEvent->where, &growLimits);				if (newSize != 0) {					SizeWindow(stWindow, LoWord(newSize), HiWord(newSize), true);				}			}		break;		case inContent:			if (theWindow == stWindow) {				if (theWindow != FrontWindow()) {					SelectWindow(stWindow);				}				recordMouseDown(theEvent);			}		break;		case inGoAway:			if ((theWindow == stWindow) &&				(TrackGoAway(stWindow, theEvent->where))) {					/* HideWindow(stWindow); noop for now */			}		break;	}}void InitMacintosh(void) {	MaxApplZone();	InitGraf(&qd.thePort);	InitFonts();	FlushEvents(everyEvent, 0);	InitWindows();	InitMenus();	TEInit();	InitDialogs(NULL);	InitCursor();}void SetUpMenus(void) {	InsertMenu(appleMenu = NewMenu(appleID, "\p\024"), 0);	InsertMenu(fileMenu  = NewMenu(fileID,  "\pFile"), 0);	InsertMenu(editMenu  = NewMenu(editID,  "\pEdit"), 0);	DrawMenuBar();	AddResMenu(appleMenu, 'DRVR');	AppendMenu(fileMenu, "\pQuit");	AppendMenu(editMenu, "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear");}void SetColorEntry(int index, int red, int green, int blue) {	(*stColorTable)->ctTable[index].value = index;	(*stColorTable)->ctTable[index].rgb.red = red;	(*stColorTable)->ctTable[index].rgb.green = green;	(*stColorTable)->ctTable[index].rgb.blue = blue;}void FreePixmap(void) {	if (stPixMap != nil) {		DisposePixMap(stPixMap);		stPixMap = nil;	}	if (stColorTable != nil) {		DisposeHandle((void *) stColorTable);		stColorTable = nil;	}}void SetUpPixmap(void) {	int i, r, g, b;	stColorTable = (CTabHandle) NewHandle(sizeof(ColorTable) + (256 * sizeof(ColorSpec)));	(*stColorTable)->ctSeed = GetCTSeed();	(*stColorTable)->ctFlags = 0;	(*stColorTable)->ctSize = 255;	/* 1-bit colors (monochrome) */	SetColorEntry(0, 65535, 65535, 65535);	/* white */	SetColorEntry(1,     0,     0,     0);	/* black */	/* additional colors for 2-bit color */	SetColorEntry(2, 32768, 32768, 32768);	/* 50% gray */	SetColorEntry(3, 65535, 65535,     0);	/* yellow */	/* additional colors for 4-bit color */	SetColorEntry( 4, 65535,     0,     0);	/* red */	SetColorEntry( 5,     0, 65535,     0);	/* green */	SetColorEntry( 6,     0,     0, 65535);	/* blue */	SetColorEntry( 7,     0, 65535, 65535);	/* cyan */	SetColorEntry( 8, 65535,     0, 65535);	/* magenta */	SetColorEntry( 9,  8192,  8192,  8192);	/* 1/8 gray */	SetColorEntry(10, 16384, 16384, 16384);	/* 2/8 gray */	SetColorEntry(11, 24576, 24576, 24576);	/* 3/8 gray */	SetColorEntry(12, 32768, 32768, 32768);	/* 4/8 gray */	SetColorEntry(13, 40959, 40959, 40959);	/* 5/8 gray */	SetColorEntry(14, 49151, 49151, 49151);	/* 6/8 gray */	SetColorEntry(15, 57343, 57343, 57343);	/* 7/8 gray */	/* additional colors for 8-bit color */	/* 24 more shades of gray (does not repeat 1/8th increments) */	SetColorEntry(16,  2048,  2048,  2048);	/*  1/32 gray */	SetColorEntry(17,  4096,  4096,  4096);	/*  2/32 gray */	SetColorEntry(18,  6144,  6144,  6144);	/*  3/32 gray */	SetColorEntry(19, 10240, 10240, 10240);	/*  5/32 gray */	SetColorEntry(20, 12288, 12288, 12288);	/*  6/32 gray */	SetColorEntry(21, 14336, 14336, 14336);	/*  7/32 gray */	SetColorEntry(22, 18432, 18432, 18432);	/*  9/32 gray */	SetColorEntry(23, 20480, 20480, 20480);	/* 10/32 gray */	SetColorEntry(24, 22528, 22528, 22528);	/* 11/32 gray */	SetColorEntry(25, 26624, 26624, 26624);	/* 13/32 gray */	SetColorEntry(26, 28672, 28672, 28672);	/* 14/32 gray */	SetColorEntry(27, 30720, 30720, 30720);	/* 15/32 gray */	SetColorEntry(28, 34815, 34815, 34815);	/* 17/32 gray */	SetColorEntry(29, 36863, 36863, 36863);	/* 18/32 gray */	SetColorEntry(30, 38911, 38911, 38911);	/* 19/32 gray */	SetColorEntry(31, 43007, 43007, 43007);	/* 21/32 gray */	SetColorEntry(32, 45055, 45055, 45055);	/* 22/32 gray */	SetColorEntry(33, 47103, 47103, 47103);	/* 23/32 gray */	SetColorEntry(34, 51199, 51199, 51199);	/* 25/32 gray */	SetColorEntry(35, 53247, 53247, 53247);	/* 26/32 gray */	SetColorEntry(36, 55295, 55295, 55295);	/* 27/32 gray */	SetColorEntry(37, 59391, 59391, 59391);	/* 29/32 gray */	SetColorEntry(38, 61439, 61439, 61439);	/* 30/32 gray */	SetColorEntry(39, 63487, 63487, 63487);	/* 31/32 gray */	/* The remainder of color table defines a color cube with six steps	   for each primary color. Note that the corners of this cube repeat	   previous colors, but simplifies the mapping between RGB colors and	   color map indices. This color cube spans indices 40 through 255.	*/	for (r = 0; r < 6; r++) {		for (g = 0; g < 6; g++) {			for (b = 0; b < 6; b++) {				i = 40 + ((36 * r) + (6 * b) + g);				if (i > 255) error("index out of range in color table compuation");				SetColorEntry(i, (r * 65535) / 5, (g * 65535) / 5, (b * 65535) / 5);			}		}	}	stPixMap = NewPixMap();	(*stPixMap)->pixelType = 0; /* chunky */	(*stPixMap)->cmpCount = 1;	(*stPixMap)->pmTable = stColorTable;}void SetUpWindow(void) {	Rect windowBounds = { 44, 8, 408, 648 };  /* default window bounds */	Rect screen;	int right, bottom;	if (savedWindowSize != 0) {		right  = windowBounds.left + ((unsigned) savedWindowSize >> 16);		bottom = windowBounds.top  + (savedWindowSize & 0xFFFF);	} else {		right  = windowBounds.right;		bottom = windowBounds.bottom;	}	/* minimum size is 64 x 64 */	right  = ( right > (windowBounds.left + 64)) ?  right : (windowBounds.left + 64);	bottom = (bottom > (windowBounds.top  + 64)) ? bottom : (windowBounds.top  + 64);	/* maximum bottom-right is screen bottom-right */	screen = qd.screenBits.bounds;	right  = ( right <= screen.right)  ?  right : (screen.right  - 8);	bottom = (bottom <= screen.bottom) ? bottom : (screen.bottom - 8);	windowBounds.right = right;	windowBounds.bottom = bottom;	stWindow = NewCWindow(0L, &windowBounds, "\pSqueak", true, documentProc, (WindowPtr) -1L, true, 0);}void SetWindowSize(void);void SetWindowSize(void) {	Rect screen;	int width, height, maxWidth, maxHeight;	char title[256];		if (savedWindowSize != 0) {		width  = (unsigned) savedWindowSize >> 16;		height = savedWindowSize & 0xFFFF;	} else {		width  = 640;		height = 480;	}	/* minimum size is 64 x 64 */	width  = ( width > 64) ?   width : 64;	height = (height > 64) ?  height : 64;	/* maximum size is screen size */	screen = qd.screenBits.bounds;	maxWidth  = (screen.right  - screen.left) - 16;	maxHeight = (screen.bottom - screen.top)  - 52;	width  = ( width <= maxWidth)  ?  width : maxWidth;	height = (height <= maxHeight) ? height : maxHeight;	SizeWindow(stWindow, width, height, true);	strcpy(title, shortImageName);	c2pstr(title);	SetWTitle(stWindow, (unsigned char *)title);}/*** Event Recording Functions ***/int recordKeystroke(EventRecord *theEvent) {	int keystate;	/* keystate: low byte is the ascii character; next 4 bits are modifier bits */	keystate =		(modifierMap[(theEvent->modifiers >> 8) & 0x1F] << 8) |		(theEvent->message & 0xFF);	if (keystate == interruptKeycode) {		/* Note: interrupt key is "meta"; it not reported as a keystroke */		interruptPending = true;		interruptCheckCounter = 0;	} else {		keyBuf[keyBufPut] = keystate;		keyBufPut = (keyBufPut + 1) % KEYBUF_SIZE;		if (keyBufGet == keyBufPut) {			/* buffer overflow; drop the last character */			keyBufGet = (keyBufGet + 1) % KEYBUF_SIZE;			keyBufOverflows++;		}	}}int recordMouseDown(EventRecord *theEvent) {	int stButtons;	stButtons = 4;		/* red button by default */	if ((theEvent->modifiers & optionKey) != 0) {		stButtons = 2;	/* yellow button if option down */	}	if ((theEvent->modifiers & cmdKey) != 0) {		stButtons = 1;	/* blue button if command down */	}	/* button state: low three bits are mouse buttons; next 4 bits are modifier bits */	buttonState =		(modifierMap[(theEvent->modifiers >> 8) & 0x1F] << 3) |		(stButtons & 0x7);}int recordModifierButtons(EventRecord *theEvent) {	int stButtons = 0;	if (Button()) {		stButtons = buttonState & 0x7;	} else {		stButtons = 0;	}	/* button state: low three bits are mouse buttons; next 4 bits are modifier bits */	buttonState =		(modifierMap[(theEvent->modifiers >> 8) & 0x1F] << 3) |		(stButtons & 0x7);}/*** I/O Primitives ***/int ioBeep(void) {	SysBeep(1000);}int ioGetButtonState(void) {	ioProcessEvents();  /* process all pending events */	return buttonState;}int ioGetKeystroke(void) {	int keystate;	ioProcessEvents();  /* process all pending events */	if (keyBufGet == keyBufPut) {		return -1;  /* keystroke buffer is empty */	} else {		keystate = keyBuf[keyBufGet];		keyBufGet = (keyBufGet + 1) % KEYBUF_SIZE;		/* set modifer bits in buttonState to reflect the last keystroke fetched */		buttonState = ((keystate >> 5) & 0xF8) | (buttonState & 0x7);	}	return keystate;}int ioMicroMSecs(void) {	/* millisecond clock based on microsecond timer (about 60 times slower than ioMSecs!!) */	UnsignedWide microTicks;	Microseconds(&microTicks);	return (microTicks.lo / 1000) + (microTicks.hi * 4294967);}int ioMousePoint(void) {	Point p;	ioProcessEvents();  /* process all pending events */	if (windowActive) {		GetMouse(&p);	} else {		/* don't report mouse motion if window is not active */		p = savedMousePosition;	}	return (p.h << 16) | (p.v & 0xFFFF);  /* x is high 16 bits; y is low 16 bits */}int ioPeekKeystroke(void) {	int keystate;	ioProcessEvents();  /* process all pending events */	if (keyBufGet == keyBufPut) {		return -1;  /* keystroke buffer is empty */	} else {		keystate = keyBuf[keyBufGet];		/* set modifer bits in buttonState to reflect the last keystroke peeked at */		buttonState = ((keystate >> 5) & 0xF8) | (buttonState & 0x7);	}	return keystate;}int ioProcessEvents(void) {	/* This is a noop when running as a plugin; the browser handles events. */	int maxPollsPerSec = 30;	static clock_t nextPollTick = 0;#ifndef PLUGIN	if (clock() > nextPollTick) {		/* time to process events! */		while (HandleEvents()) {			/* process all pending events */		}		/* wait a while before trying again */		nextPollTick = clock() + (CLOCKS_PER_SEC / maxPollsPerSec);	}#endif}int ioScreenSize(void) {	int w = 10, h = 10;	if (stWindow != nil) {		w = stWindow->portRect.right - stWindow->portRect.left;		h = stWindow->portRect.bottom - stWindow->portRect.top;	}	return (w << 16) | (h & 0xFFFF);  /* w is high 16 bits; h is low 16 bits */}int ioSeconds(void) {	struct tm timeRec;	time_t time1904, timeNow;	/* start of ANSI epoch is midnight of Jan 1, 1904 */	timeRec.tm_sec   = 0;	timeRec.tm_min   = 0;	timeRec.tm_hour  = 0;	timeRec.tm_mday  = 1;	timeRec.tm_mon   = 0;	timeRec.tm_year  = 4;	timeRec.tm_wday  = 0;	timeRec.tm_yday  = 0;	timeRec.tm_isdst = 0;	time1904 = mktime(&timeRec);	timeNow = time(NULL);	/* Squeak epoch is Jan 1, 1901, 3 non-leap years earlier than ANSI one */	return (timeNow - time1904) + (3 * 365 * 24 * 60 * 60);}int ioSetCursor(int cursorBitsIndex, int offsetX, int offsetY, int depth) {	Cursor macCursor;	int i, j, data, mask, word;	if (depth == 1) {		for (i = 0; i < 16; i++) {			macCursor.data[i] = (checkedLongAt(cursorBitsIndex + (4 * i)) >> 16) & 0xFFFF;			macCursor.mask[i] = (checkedLongAt(cursorBitsIndex + (4 * i)) >> 16) & 0xFFFF;		}	} else {		for (i = 0; i < 16; i++) {			data = mask = 0;			word = checkedLongAt(cursorBitsIndex + (4 * i));			for (j = 0; j < 16; j++) {				data |= (word >> j) & (1 << j);				mask |= (word >> (j+1)) & (1 << j);			}			macCursor.data[i] = data;			macCursor.mask[i] = mask ^ -1;		}	}	/* Squeak hotspot offsets are negative; Mac's are positive */	macCursor.hotSpot.h = -offsetX;	macCursor.hotSpot.v = -offsetY;	SetCursor(&macCursor);}int ioShowDisplay(	int dispBitsIndex, int width, int height, int depth,	int affectedL, int affectedR, int affectedT, int affectedB) {	Rect		dstRect = { 0, 0, 0, 0 };	Rect		srcRect = { 0, 0, 0, 0 };	RgnHandle	maskRect = nil;	if (stWindow == nil) {		return;	}	dstRect.left	= 0;	dstRect.top		= 0;	dstRect.right	= width;	dstRect.bottom	= height;	srcRect.left	= 0;	srcRect.top		= 0;	srcRect.right	= width;	srcRect.bottom	= height;	(*stPixMap)->baseAddr = (void *) dispBitsIndex;	/* Note: top three bits of rowBytes indicate this is a PixMap, not a BitMap */	(*stPixMap)->rowBytes = (((((width * depth) + 31) / 32) * 4) & 0x1FFF) | 0x8000;	(*stPixMap)->bounds = srcRect;	(*stPixMap)->pixelSize = depth;	(*stPixMap)->cmpSize = depth;	/* create a mask region so that only the affected rectangle is copied */	maskRect = NewRgn();	SetRectRgn(maskRect, affectedL, affectedT, affectedR, affectedB);	SetPort(stWindow);	CopyBits((BitMap *) *stPixMap, &stWindow->portBits, &srcRect, &dstRect, srcCopy, maskRect);	DisposeRgn(maskRect);}/*** Image File Naming ***/void RecordFullPathForImageName(char *localImageName) {	int offset, localNameSize, i;	offset = dir_PathToWorkingDir(imageName, IMAGE_NAME_SIZE);	/* copy the file name into a null-terminated C string */	localNameSize = strlen(localImageName);	for (i = 0; i <= localNameSize; i++) {		/* append localName, including terminator */		imageName[i + offset] = localImageName[i];	}}int imageNameSize(void) {	return strlen(imageName);}int imageNameGetLength(int sqImageNameIndex, int length) {	char *sqImageName = (char *) sqImageNameIndex;	int count, i;	count = strlen(imageName);	count = (length < count) ? length : count;	/* copy the file name into the Squeak string */	for (i = 0; i < count; i++) {		sqImageName[i] = imageName[i];	}	return count;}int imageNamePutLength(int sqImageNameIndex, int length) {	char *sqImageName = (char *) sqImageNameIndex;	int count, i;	count = (IMAGE_NAME_SIZE < length) ? IMAGE_NAME_SIZE : length;	/* copy the file name into a null-terminated C string */	for (i = 0; i < count; i++) {		imageName[i] = sqImageName[i];	}	imageName[count] = 0;	return count;}/*** Clipboard Support (text only for now) ***/void SetUpClipboard(void) {	/* allocate clipboard in the system heap to support really big copy/paste */	THz oldZone;	oldZone = GetZone();	SetZone(SystemZone());	clipboardBuffer = NewHandle(0);	SetZone(oldZone);}void FreeClipboard(void) {	if (clipboardBuffer != nil) {		DisposeHandle(clipboardBuffer);		clipboardBuffer = nil;	}}int clipboardReadIntoAt(int count, int byteArrayIndex, int startIndex) {	long clipSize, charsToMove;	char *srcPtr, *dstPtr, *end;	clipSize = clipboardSize();	charsToMove = (count < clipSize) ? count : clipSize;	srcPtr = (char *) *clipboardBuffer;	dstPtr = (char *) byteArrayIndex + startIndex;	end = srcPtr + charsToMove;	while (srcPtr < end) {		*dstPtr++ = *srcPtr++;	}	return charsToMove;}int clipboardSize(void) {	long count, offset;	count = GetScrap(clipboardBuffer, 'TEXT', &offset);	if (count < 0) {		return 0;	} else {		return count;	}}int clipboardWriteFromAt(int count, int byteArrayIndex, int startIndex) {	ZeroScrap();	PutScrap(count, 'TEXT', (char *) (byteArrayIndex + startIndex));}/*** Profiling ***/int clearProfile(void) {#ifdef MAKE_PROFILE	ProfilerClear();#endif}int dumpProfile(void) {#ifdef MAKE_PROFILE	ProfilerDump("\pProfile.out");#endif}int startProfiling(void) {#ifdef MAKE_PROFILE	ProfilerSetStatus(true);#endif}int stopProfiling(void) {#ifdef MAKE_PROFILE	ProfilerSetStatus(false);#endif}/*** Plugin Support ***/int plugInInit(char *fullImagePath) {	if (memory == nil) {		return;	/* failed to read image */	}	/* check the interpreter's size assumptions for basic data types */	if (sizeof(int) != 4) {		error("This C compiler's integers are not 32 bits.");	}	if (sizeof(double) != 8) {		error("This C compiler's floats are not 64 bits.");	}	if (sizeof(time_t) != 4) {		error("This C compiler's time_t's are not 32 bits.");	}	strcpy(imageName, fullImagePath);	dir_PathToWorkingDir(vmPath, VMPATH_SIZE);	SetUpClipboard();	SetUpPixmap();	sqFileInit();	joystickInit();}int plugInShutdown(void) {	snd_Stop();	FreeClipboard();	FreePixmap();	if (memory != nil) {		DisposePtr((void *) memory);		memory = nil;	}}/*** Main ***/#ifndef PLUGIN#ifdef SHLIBvoid shlib_main() {	ProcessSerialNumber psn;	ProcessInfoRec info;	short err;#elsevoid main(void) {#endif	EventRecord theEvent;	FILE *f;	int availableMemory;	InitMacintosh();	SetUpMenus();	SetUpClipboard();	SetUpWindow();	SetUpPixmap();	sqFileInit();	joystickInit();#ifdef SHLIB	/* use the application's name */	info.processInfoLength = sizeof(info);	info.processName = 0;	info.processAppSpec = &appSpec;	err = GetCurrentProcess(&psn);	if (err != noErr) {		fprintf(stderr, "error %d getting current process\n", err);		return;	}	err = GetProcessInformation(&psn, &info);	if (err != noErr) {		fprintf(stderr, "error %d getting process info\n", err);		return;	}	strcpy(shortImageName, p2cstr(appSpec.name));#else	/* install apple event handlers and wait for open event */	InstallAppleEventHandlers();	while (shortImageName[0] == 0) {		GetNextEvent(everyEvent, &theEvent);		if (theEvent.what == kHighLevelEvent) {			AEProcessAppleEvent(&theEvent);		}	}#endif	RecordFullPathForImageName(shortImageName);	/* check the interpreter's size assumptions for basic data types */	if (sizeof(int) != 4) {		error("This C compiler's integers are not 32 bits.");	}	if (sizeof(double) != 8) {		error("This C compiler's floats are not 64 bits.");	}	if (sizeof(time_t) != 4) {		error("This C compiler's time_t's are not 32 bits.");	}#ifdef MAKE_PROFILE	ProfilerInit(collectDetailed, bestTimeBase, 1000, 50);	ProfilerSetStatus(false);	ProfilerClear();#endif	/* compute the desired memory allocation */	availableMemory = MaxBlock() - 80000;  /* reserve a little memory (at least 50000!) */	/******	  Note: This is platform-specific. On the Mac, the user specifies the desired	    memory partition for each application using the Finder's Get Info command. On	    other platforms, it would be specified in other ways (e.g, by a command line	    argument. The maximum size of the object heap is fixed at at startup. If you	    run out, you must save the image and restart with more memory.	  Note: Some memory must be reserved for Mac toolbox calls, sound buffers, etc.	    A 30K reserve is too little. 40K allows Squeak to run but crashes if the	    console is opened. 50K allows the console to be opened (with and w/o the	    profiler). I added another 30K to provide for sound buffers and reliability.	******/	/* uncomment the following when using the C transcript window for debugging: */	//printf("Move this window, then hit CR\n"); getchar();	/* read the image file and allocate memory for Squeak heap */	f = fopen(imageName, "rb");	if (f == NULL) {		/* give a Mac-specific error message if image file is not found */		printf("Could not open the Squeak image file '%s'\n\n", imageName);		printf("There are several ways to open a Squeak image file. You can:\n");		printf("  1. Double-click on the desired image file.\n");		printf("  2. Drop the image file icon onto the Squeak application or an alias to it.\n");		printf("  3. Name your image 'clone.image' and put it in the same folder as the\n");		printf("     Squeak application, then double-click on the Squeak application.\n\n");		printf("Press the return key to exit.\n");		getchar();		printf("Aborting...\n");		exit(-1);	}		readImageFromFileHeapSize(f, availableMemory);	fclose(f);	SetWindowSize();	/* run Squeak */	interpret();}#endif
