/******************************************************************************
FILE
    SqView.m
DESCRIPTION
	NeXTstep user Interface for Squeak.
AUTHOR
	<PJB> Pascal J. Bourguignon
MODIFICATIONS
	1998/06/12 <PJB> Creation.
LEGAL
	Copyright Pascal J. Bourguignon 1998 - 1998

	This program is free software; you can redistribute it and/or
	modify it under the terms of the version 2 of the GNU General Public 
	License as published by the Free Software Foundation.
	
	This program is distributed in the hope that it will be useful, but 
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
	hereafter for more details.
******************************************************************************/
#import "SqView.h"
#import "SqApplication.h"
#import <ctype.h>

#define debug(a)
#define DEBUG_KEYDOWN



// ------------------------------------------------------------------------- //

@interface SqView(Private)

	
	-(NXBitmapImageRep*)extractPixels_1_to_2:(void*)srcBits
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_2_to_2:(void*)srcBits
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_8_to_2:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_8_to_8:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_8_to_16:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_8_to_32:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_16_to_16:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	-(NXBitmapImageRep*)extractPixels_32_to_32:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position;
	
	-(NXBitmapImageRep*)computeBitmapFromBitsIndex:(void*)srcBits
					width:(int)width height:(int)height depth:(int)depth 
					left:(int)left right:(int)right 
					top:(int)top bottom:(int)bottom
					position:(NXPoint*)position;
	
	-(void)getRect:(NXRect*)rect fromSqLeft:(int)left top:(int)top
			right:(int)right bottom:(int)bottom;
	-(void)getPoint:(NXPoint*)point fromSq:(int)x:(int)y;
	-(void)point:(NXPoint*)point toSq:(int*)x:(int*)y;
	-(void)updateButtonStateWith:(int)keyFlags;
	
@end // SqView(Private).

// ------------------------------------------------------------------------- //

@implementation SqView(Private)

#define CHECKANDRETURN(expr) \
	{ NXBitmapImageRep* bitmap=expr; if(bitmap!=0){return(bitmap);}\
	fprintf(stderr,"initData:%08x\n"\
				"pixelsWide:%d\n"\
				"pixelsHigh:%d\n"\
				"bitsPerSample:%d\n"\
				"samplesPerPixel:%d\n"\
				"hasAlpha:%d\n"\
				"isPlanar:%d\n"\
				"colorSpace:%d\n"\
				"bytesPerRow:%d\n"\
				"bitsPerPixel:%d\n",\
				(int)dBits,right-left,bottom-top,bitsPerSample,\
				samplesPerPixel,NO,NO,colorSpace,bytesPerRow,bitsPerPixel);\
		return(0);\
	}
	
	-(NXBitmapImageRep*)extractPixels_1_to_2:(void*)srcBits
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		static unsigned char One_to_Two[16]={
			0x00,0x03,0x0c,0x0f,
			0x30,0x33,0x3c,0x3f,
			0xc0,0xc3,0xcc,0xcf,
			0xf0,0xf3,0xfc,0xff
		};
		unsigned char*      sBits=srcBits;
		unsigned char*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 i;
		int                 srcY;
		
		if((srcPixelWidth%8)!=0){
			fprintf(stderr,"It would be better to have srcPixelWidth%%8==0 "
					"instead of %d.\n",srcPixelWidth);
			return(0);
		}
		
		sRowSlots=srcPixelWidth/8;
		left=left&(~7);
		right=(right+7)&(~7);
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=2;
		samplesPerPixel=1;
		bytesPerRow=(right-left)/4;
		bitsPerPixel=2;
		colorSpace=NX_OneIsBlackColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned char*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left/8;
		maxX=right/8;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				unsigned char src=sBits[srcX];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				unsigned char src=sBits[srcX^3];
#endif
				dBits[i++]=One_to_Two[src>>4];
				dBits[i++]=One_to_Two[src&0xf];
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_1_to_2:...;
	


	-(NXBitmapImageRep*)extractPixels_2_to_2:(void*)srcBits
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned char*      sBits=srcBits;
		unsigned char*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		unsigned char*      map=Two_to_Two;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 i;
		int                 srcY;
		
		if((srcPixelWidth%4)!=0){
			fprintf(stderr,"It would be better to have srcPixelWidth%%4==0 "
					"instead of %d.\n",srcPixelWidth);
			return(0);
		}
		
		sRowSlots=srcPixelWidth/4;
		left=left&(~3);
		right=(right+3)&(~3);
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=2;
		samplesPerPixel=1;
		bytesPerRow=(right-left)/4;
		bitsPerPixel=2;
		colorSpace=NX_OneIsWhiteColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned char*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left/4;
		maxX=right/4;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=map[sBits[srcX]];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=map[sBits[srcX^3]];
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_2_to_2;
	


	-(NXBitmapImageRep*)extractPixels_8_to_2:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned char*      sBits=srcBits;
		unsigned char*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		unsigned char*      map=colorMap2Gray;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 i;
		int                 srcY;
		
		sRowSlots=srcPixelWidth;
		left=left&(~3);
		right=(right+3)&(~3);
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=2;
		samplesPerPixel=1;
		bytesPerRow=(right-left)/4;
		bitsPerPixel=2;
		colorSpace=NX_OneIsWhiteColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned char*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX+=4){
#ifdef __BIG_ENDIAN__
				dBits[i++]=(map[sBits[srcX]]<<6)
						|(map[sBits[srcX+1]]<<4)
						|(map[sBits[srcX+2]]<<2)
						|(map[sBits[srcX+3]]);
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=(map[sBits[srcX+3]]<<6)
						|(map[sBits[srcX+2]]<<4)
						|(map[sBits[srcX+1]]<<2)
						|(map[sBits[srcX]]);
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_8_to_2;
	


	-(NXBitmapImageRep*)extractPixels_8_to_8:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned char*      sBits=srcBits;
		unsigned char*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		unsigned char*      map=colorMap8Gray;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 srcY;
		int                 i;
		
		sRowSlots=srcPixelWidth;
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=8;
		samplesPerPixel=1;
		bytesPerRow=right-left;
		bitsPerPixel=8;
		colorSpace=NX_OneIsWhiteColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned char*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=map[sBits[srcX]];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=map[sBits[srcX^3]];
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_8_to_8;
	


	-(NXBitmapImageRep*)extractPixels_8_to_16:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned char*      sBits=srcBits;
		unsigned short*     dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		unsigned short*     map=colorMap16;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 srcY;
		int                 i;
		
		sRowSlots=srcPixelWidth;
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=4;
		samplesPerPixel=3;
		bytesPerRow=(right-left)*2;
		bitsPerPixel=16;
		colorSpace=NX_RGBColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned short*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=map[sBits[srcX]];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=map[sBits[srcX^3]];
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_8_to_16;
	


	-(NXBitmapImageRep*)extractPixels_8_to_32:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned char*      sBits=srcBits;
		unsigned long*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;

		unsigned long*      map=colorMap32;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 srcY;
		int                 i;
		
		sRowSlots=srcPixelWidth;
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=8;
		samplesPerPixel=3;
		bytesPerRow=(right-left)*4;
		bitsPerPixel=32;
		colorSpace=NX_RGBColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned long*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=map[sBits[srcX]];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=map[sBits[srcX^3]];
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_8_to_32;
	


	-(NXBitmapImageRep*)extractPixels_16_to_16:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned short*     sBits=srcBits;
		unsigned short*     dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 srcY;
		int                 i;
		
		sRowSlots=srcPixelWidth;
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=4;
		samplesPerPixel=3;
		bytesPerRow=(right-left)*2;
		bitsPerPixel=16;
		colorSpace=NX_RGBColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned short*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=sBits[srcX];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=ntohs(sBits[srcX^1]);
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_16_to_16;
	


	-(NXBitmapImageRep*)extractPixels_32_to_32:(void*)srcBits 
			srcPixelWidth:(int)srcPixelWidth
			left:(int)left right:(int)right 
			top:(int)top bottom:(int)bottom
			position:(NXPoint*)position
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		unsigned long*      sBits=srcBits;
		unsigned long*      dBits;
		int                 bitsPerSample;
		int                 samplesPerPixel;
		int                 bytesPerRow;
		int                 bitsPerPixel;
		NXColorSpace        colorSpace;
		
		int                 neededBytes;
		int                 sRowSlots;
		int                 minY;
		int                 maxY;
		int                 minX;
		int                 maxX;
		int                 srcY;
		int                 i;
		
		sRowSlots=srcPixelWidth;
		[self getPoint:position fromSq:left :bottom];
		
		bitsPerSample=8;
		samplesPerPixel=3;
		bytesPerRow=(right-left)*4;
		bitsPerPixel=32;
		colorSpace=NX_RGBColorSpace;

		neededBytes=bytesPerRow*(bottom-top);
		dBits=(unsigned long*)malloc(neededBytes);
		
		minY=top*sRowSlots;
		maxY=bottom*sRowSlots;
		minX=left;
		maxX=right;
		
		i=0;
		for(srcY=minY;srcY<maxY;srcY+=sRowSlots){
			int maxXY=srcY+maxX;
			int srcX;
			for(srcX=srcY+minX;srcX<maxXY;srcX++){
#ifdef __BIG_ENDIAN__
				dBits[i++]=sBits[srcX];
#else
				//	0	->	3		4	->	7
				//	1	->	2		5	->	6
				//	2	->	1		6	->	5
				//	3	->	0		7	->	4
				dBits[i++]=ntohl(sBits[srcX]);
#endif
			}
		}
		
		CHECKANDRETURN([[NXBitmapImageRep alloc] initData:(void*)dBits 
				pixelsWide:right-left
				pixelsHigh:bottom-top
				bitsPerSample:bitsPerSample
				samplesPerPixel:samplesPerPixel
				hasAlpha:NO
				isPlanar:NO
				colorSpace:colorSpace
				bytesPerRow:bytesPerRow
				bitsPerPixel:bitsPerPixel]);
	}//extractPixels_32_to_32;
	

	-(NXWindowDepth)depthLimit
	{
		NXWindowDepth wdepth=[window depthLimit];
		if(wdepth==NX_DefaultDepth){
			wdepth=[Window defaultDepthLimit];
		}
		return(wdepth);
	}//depthLimit;


	-(NXBitmapImageRep*)computeBitmapFromBitsIndex:(void*)srcBits
					width:(int)width height:(int)height depth:(int)depth 
					left:(int)left right:(int)right 
					top:(int)top bottom:(int)bottom
					position:(NXPoint*)position
	{
		/*
			It seems that NXImage will replace its NXBitmapImageRep with a
			NXCachedImageRep of the whole bitmap upon receiving a 
			composite:fromRect:toPoint: message.
			Therefore:
			  1- it is useless to keep our own "cached" image;
			  2- we may as well copy to the right format & depth the affected
			     rectangle in a temporary bitmap, and draw it directly.
		*/
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		
		switch(depth){
		case 1:
			return([self extractPixels_1_to_2:srcBits srcPixelWidth:width
					left:left right:right top:top bottom:bottom 
					position:position]);
			break;
		case 2:
			return([self extractPixels_2_to_2:srcBits srcPixelWidth:width
					left:left right:right top:top bottom:bottom 
					position:position]);
			break;
		case 8:
			switch([self depthLimit]){
			case NX_TwoBitGrayDepth:
				return([self extractPixels_8_to_2:srcBits srcPixelWidth:width
						left:left right:right top:top bottom:bottom 
					position:position]);
				break;
			case NX_EightBitGrayDepth:
				return([self extractPixels_8_to_8:srcBits srcPixelWidth:width
						left:left right:right top:top bottom:bottom 
					position:position]);
				break;
			case NX_TwelveBitRGBDepth:
				return([self extractPixels_8_to_16:srcBits srcPixelWidth:width
						left:left right:right top:top bottom:bottom 
					position:position]);
				break;
			case NX_TwentyFourBitRGBDepth:
			default:
				return([self extractPixels_8_to_32:srcBits srcPixelWidth:width
						left:left right:right top:top bottom:bottom 
					position:position]);
			}
			break;
		case 16:
			return([self extractPixels_16_to_16:srcBits srcPixelWidth:width
					left:left right:right top:top bottom:bottom 
					position:position]);
			break;
		case 32:
			return([self extractPixels_32_to_32:srcBits srcPixelWidth:width
					left:left right:right top:top bottom:bottom 
					position:position]);
			break;
		default:
			switch(NXRunAlertPanel("Error",
				"NeXTSTEP user interface for Squeak doesn't support "
				"image depth of %d.\n",
				"Continue","Quit",NULL,depth)){
			case NX_ALERTDEFAULT:
				return(0);
			case NX_ALERTALTERNATE:
				[NXApp squeakTerminate];
				return(0);
			case NX_ALERTERROR:
			default:
				fprintf(stderr,"NeXTSTEP user interface for Squeak doesn't "
				"support image depth of %d.\n",depth);
				[NXApp squeakTerminate];
				return(0);
			}
		}
	}//computeBitmapFromBitsIndex:width:height:depth:left:right:top:bottom:;


	/*
		The bitmaps coming from Squeak are not flipped, but its coordinate
		system is. Here are two methods to flip the coordinates so we can
		leave: [self setFlipped:NO].
	*/
	
	-(void)getRect:(NXRect*)rect fromSqLeft:(int)left top:(int)top
			right:(int)right bottom:(int)bottom
	{
		rect->origin.x=left;
		rect->origin.y=bounds.size.height-bottom;
		rect->size.width=right-left;
		rect->size.height=bottom-top;
	}//getRect:fromSqLeft:top:right:bottom:;

	
	-(void)getPoint:(NXPoint*)point fromSq:(int)x:(int)y
	{
		point->x=x;
		point->y=bounds.size.height-y;
	}//getPoint:fromSq::;

	
	-(void)point:(NXPoint*)point toSq:(int*)x:(int*)y
	{
		(*x)=point->x;
		(*y)=bounds.size.height-point->y;
	}//point:toSq::;


	/*
		Squeak bits:    <command><option><control><shift>
	*/
	typedef enum {
		sqMod_command=64,
		sqMod_option=32,
		sqMod_control=16,
		sqMod_shift=8,
		sqMod_red=4,
		sqMod_yellow=2,
		sqMod_blue=1
	}	sqModT;

	/*
		We want to keep the synchronization between the keys and the
		modifiers transmitted with getButtonState, therefore we compute
		the buttonState when mouse buttons change or when keys are asked
		by Squeak.
	
		NeXT event flags are:
			20	Command
			19	Alternate
			18	Control
			17	Shift
			16	AlphaLock or Shift

		Hence the formula: ((eventFlags>>14)&0x78) to map them to sqMod.
	*/
	
	-(void)updateButtonStateWith:(int)keyFlags
	{
		buttonState=((keyFlags>>14)&0x78);
		if([redButton isPressedWhen:eventFlags]){
			buttonState|=sqMod_red;
		}
		if([yellowButton isPressedWhen:eventFlags]){
			buttonState|=sqMod_yellow;
		}
		if([blueButton isPressedWhen:eventFlags]){
			buttonState|=sqMod_blue;
		}
//fprintf(stderr,"buttonstate=%02x\r",buttonState);
	}//updateButtonStateWith:;



@end // SqView(Private).

// ------------------------------------------------------------------------- //

@implementation SqView

	-(id)initFrame:(const NXRect*)frameRect
	{
		self=[super initFrame:frameRect];
		if(self!=0){
			cursor=0;
			buttonState=0;
			isFullScreen=NO;
			keyHead=0;
			keyTail=0;
			cachedImage=0;
			bitsRgb=0;
			bitsRgbSize=0;
			[self initializeTransparentCursor];
			[self initializeSqueakColorMap];
			[self setFlipped:NO]; // If you change this, update 
			// getRect:fromSqLeft:top:right:bottom: and point:toSq::.
			[self setOpaque:YES];
			redButton=[[SqButton alloc]init];
			yellowButton=[[SqButton alloc]init];
			blueButton=[[SqButton alloc]init];
			[redButton setNextButton:yellowButton];
			[yellowButton setNextButton:blueButton];
			[blueButton setNextButton:redButton];
			lastBitsIndex=0;
			lastWidth=0;
			lastHeight=0;
			lastDepth=0;
		}
		return(self);
	}//initFrame:;
	
	
	-appDidInit:sender
	{
		// Warning: This object is not the delegate of NXApp.
		//          SqApplication is its own delegate, and its appDidInit:
		//          method propagates here.
		[self update];
		return(self);
	}//appDidInit:;
	
	
	-windowWillResize:sender toSize:(NXSize*)newSize
	{
		NXRect oldSize;
		int nViewWidth;
		int delta;
		
		// The Smalltalk Form are always stored with rowBytes a multiple 
		// of 32-bit. That means, 32 pixels for 1-bit pixels, 16 pixels for 
		// 2-bit pixels, ..., 1 pixel of 32-bit pixels.
		// So the width of the view could be rounded to a number depending on
		// the depth. To simplify, we'll always round to 32 pixels.
		// Note that most screen widths are multiple of 32 pixels.
		
		[window getFrame:&oldSize];
		delta=(oldSize.size.width-bounds.size.width);
		nViewWidth=newSize->width-delta;
		nViewWidth=(nViewWidth/32)*32;
		newSize->width=nViewWidth+delta;
#warning NOT FINISHED.		
		
		return(self);
	}//windowWillResize:toSize:;

/*
	When in a resizable window, we can arrange the SqView to extend on the
	whole contentView of the window, and constrain the width of the window.
	
	When in a fullScreen window, the SqView may
*/
	
	-(void)layoutInWindow
	{
		NXRect wFrame;
		NXRect vBounds;
		
		[window getFrame:&wFrame];
		
		vBounds.size.height=wFrame.size.height;
		vBounds.origin.y=0;
#warning NOT FINISHED.		
	}//layoutInWindow;
	
	
	-(id)free
	{
		// A cursor does not free its image, so we're doing it for it.
		if(cursor!=0){
			if([NXCursor currentCursor]==cursor){
				[NXArrow set];
			}
			[[cursor image]free];
			[cursor free];
		}
		if([NXCursor currentCursor]==transparentCursor){
			[NXArrow set];
		}
		[[transparentCursor image]free];
		[transparentCursor free];
		if(bitsRgb!=0){
			free(bitsRgb);
		}
		[redButton free];
		[yellowButton free];
		[blueButton free];
		free(colorMap2Gray);
		free(colorMap8Gray);
		free(colorMap16);
		free(colorMap32);
		return([super free]);
	}//free;


	-(void)initializeTransparentCursor
	{
		NXImage*            image;
		NXBitmapImageRep*   bitmap;
		NXPoint             hotSpot={0,0};
		unsigned char*      data;
		unsigned char*      mask;
		unsigned char*      planes[5];
		int                 i;
		
		bitmap=[[NXBitmapImageRep alloc] initDataPlanes:0 
				pixelsWide:16
				pixelsHigh:16
				bitsPerSample:1
				samplesPerPixel:2
				hasAlpha:YES
				isPlanar:YES
				colorSpace:NX_OneIsWhiteColorSpace
				bytesPerRow:2
				bitsPerPixel:0];
		[bitmap getDataPlanes:planes];
		data=planes[0];
		mask=planes[1];
		
		for(i=0;i<32;i++){
			data[i]=0;
			mask[i]=0;
		}
		
		image=[[NXImage alloc]init];
		[image useRepresentation:bitmap];
		transparentCursor=[[NXCursor alloc]initFromImage:image];
		[transparentCursor setHotSpot:&hotSpot];
	}//initializeTransparentCursor;
	
	
	-(void)setColorEntry:(int)i red:(int)r green:(int)g blue:(int)b
	{
		colorMap2Gray[i]=((unsigned char)
				(4.0*((float)((r)+(g)+(b))/(3.0*65536.0))))%4;
		colorMap8Gray[i]=((unsigned short)
			(256.0*((float)((r)+(g)+(b))/(3.0*65536.0))))%256;
		colorMap16[i]=((r)&0xf000)|(((g)&0xf000)>>4)|(((b)&0xf000)>>8)|0xf;
		colorMap32[i]=(((r)&0xff00)<<16)|(((g)&0xff00)<<8)|((b)&0xff00)|0xff;		
	}//setColorEntry:red:green:blue:;
	
	
	-(void)initializeSqueakColorMap
	{
		Two_to_Two=(unsigned char*)malloc(sizeof(unsigned char)*256);
		colorMap2Gray=(unsigned char*)malloc(sizeof(unsigned char)*256);
		colorMap8Gray=(unsigned char*)malloc(sizeof(unsigned char)*256);
		colorMap16=(unsigned short*)malloc(sizeof(unsigned short)*256);
		colorMap32=(unsigned long*)malloc(sizeof(unsigned long)*256);
		
		{
			unsigned char map[]={
				/*transparent:*/  0x02,
				/*black:*/        0x00,
				/*white:*/        0x03,
				/*half gray:*/    0x01};
			int i,j,k,l;
			for(i=0;i<4;i++){
				for(j=0;j<4;j++){
					for(k=0;k<4;k++){
						for(l=0;l<4;l++){
							Two_to_Two[(i<<6)|(j<<4)|(k<<2)|l]=
								(map[i]<<6)|(map[j]<<4)|(map[k]<<2)|map[l];
						}
					}
				}
			}
		}
		
#define SetColorEntry(i,r,g,b)	[self setColorEntry:i red:r green:g blue:b]
		
		/* 1-bit colors (monochrome) */
		SetColorEntry(0, 65535, 65535, 65535);    /* white or transparent */
		SetColorEntry(1,     0,     0,     0);    /* black */
		
		/* additional colors for 2-bit color */
		SetColorEntry(2, 65535, 65535, 65535);    /* opaque white */
		SetColorEntry(3, 32768, 32768, 32768);    /* 1/2 gray */
		
		/* 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, 65535,     0);   /* yellow */
		SetColorEntry( 9, 65535,     0, 65535);   /* magenta */
		SetColorEntry(10,  8192,  8192,  8192);   /* 1/8 gray */
		SetColorEntry(11, 16384, 16384, 16384);   /* 2/8 gray */
		SetColorEntry(12, 24576, 24576, 24576);   /* 3/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.
		*/
		{
			int r,g,b;
		
			for(r=0;r<6;r++){
				for(g=0;g<6;g++){
					for(b=0;b<6;b++){
						int i=40+((36*r)+(6*b)+g);
						if(i>255){
							fprintf(stderr,"index out of range "
									"in color table compuation\n");
						}
						SetColorEntry(i,(r*65535)/5,(g*65535)/5,(b*65535)/5);
					}
				}
			}
		}
	}//initializeSqueakColorMap;
	

	-(BOOL)acceptsFirstResponder
	{
		return(YES);
	}//acceptsFirstResponder;


	-(BOOL)acceptsFirstMouse
	{
		return(YES);
	}//acceptsFirstMouse;
	
	
	-(SqButton*)redButton
	{
		return(redButton);
	}//redButton;
	
	
	-(SqButton*)yellowButton
	{
		return(yellowButton);
	}//yellowButton;
	
	
	-(SqButton*)blueButton
	{
		return(blueButton);
	}//blueButton;
	
	

	-(id)mouseDown:(NXEvent*)event
	{
		eventFlags=(event->flags&0xffff0000)
					|SqButton_LeftMouseEventFlag
					|(eventFlags&SqButton_RightMouseEventFlag);
		[self updateButtonStateWith:eventFlags];
		return(self);
	}//mouseDown:;
	
	
	-(id)mouseUp:(NXEvent*)event
	{
		eventFlags=(event->flags&0xffff0000)
					|(eventFlags&SqButton_RightMouseEventFlag);
		[self updateButtonStateWith:eventFlags];
		return(self);
	}//mouseUp:;
	
	
	-(id)rightMouseDown:(NXEvent*)event
	{
		eventFlags=(event->flags&0xffff0000)
					|(eventFlags&SqButton_LeftMouseEventFlag)
					|SqButton_RightMouseEventFlag;
		[self updateButtonStateWith:eventFlags];
		return(self);
	}//rightMouseDown:;
	
	
	-(id)rightMouseUp:(NXEvent*)event
	{
		eventFlags=(event->flags&0xffff0000)
					|(eventFlags&SqButton_LeftMouseEventFlag);
		[self updateButtonStateWith:eventFlags];
		return(self);
	}//rightMouseUp:;
	


	static const unsigned char Conversion_next_to_macintosh[256]={
				/*   0 */ '\000',
				/*   1 */ '\001',
				/*   2 */ '\002',
				/*   3 */ '\003',
				/*   4 */ '\004',
				/*   5 */ '\005',
				/*   6 */ '\006',
				/*   7 */ '\007',
				/*   8 */ '\010',
				/*   9 */ '\011',
				/*  10 */ '\012',
				/*  11 */ '\013',
				/*  12 */ '\014',
				/*  13 */ '\015',
				/*  14 */ '\016',
				/*  15 */ '\017',
				/*  16 */ '\020',
				/*  17 */ '\021',
				/*  18 */ '\022',
				/*  19 */ '\023',
				/*  20 */ '\024',
				/*  21 */ '\025',
				/*  22 */ '\026',
				/*  23 */ '\027',
				/*  24 */ '\030',
				/*  25 */ '\031',
				/*  26 */ '\032',
				/*  27 */ '\033',
				/*  28 */ '\034',
				/*  29 */ '\035',
				/*  30 */ '\036',
				/*  31 */ '\037',
				/*  32 */ ' ',
				/*  33 */ '!',
				/*  34 */ '"',
				/*  35 */ '#',
				/*  36 */ '$',
				/*  37 */ '%',
				/*  38 */ '&',
				/*  39 */ '\'',
				/*  40 */ '(',
				/*  41 */ ')',
				/*  42 */ '*',
				/*  43 */ '+',
				/*  44 */ ',',
				/*  45 */ '-',
				/*  46 */ '.',
				/*  47 */ '/',
				/*  48 */ '0',
				/*  49 */ '1',
				/*  50 */ '2',
				/*  51 */ '3',
				/*  52 */ '4',
				/*  53 */ '5',
				/*  54 */ '6',
				/*  55 */ '7',
				/*  56 */ '8',
				/*  57 */ '9',
				/*  58 */ ':',
				/*  59 */ ';',
				/*  60 */ '<',
				/*  61 */ '=',
				/*  62 */ '>',
				/*  63 */ '?',
				/*  64 */ '@',
				/*  65 */ 'A',
				/*  66 */ 'B',
				/*  67 */ 'C',
				/*  68 */ 'D',
				/*  69 */ 'E',
				/*  70 */ 'F',
				/*  71 */ 'G',
				/*  72 */ 'H',
				/*  73 */ 'I',
				/*  74 */ 'J',
				/*  75 */ 'K',
				/*  76 */ 'L',
				/*  77 */ 'M',
				/*  78 */ 'N',
				/*  79 */ 'O',
				/*  80 */ 'P',
				/*  81 */ 'Q',
				/*  82 */ 'R',
				/*  83 */ 'S',
				/*  84 */ 'T',
				/*  85 */ 'U',
				/*  86 */ 'V',
				/*  87 */ 'W',
				/*  88 */ 'X',
				/*  89 */ 'Y',
				/*  90 */ 'Z',
				/*  91 */ '[',
				/*  92 */ '\\',
				/*  93 */ ']',
				/*  94 */ '^',
				/*  95 */ '_',
				/*  96 */ '`',
				/*  97 */ 'a',
				/*  98 */ 'b',
				/*  99 */ 'c',
				/* 100 */ 'd',
				/* 101 */ 'e',
				/* 102 */ 'f',
				/* 103 */ 'g',
				/* 104 */ 'h',
				/* 105 */ 'i',
				/* 106 */ 'j',
				/* 107 */ 'k',
				/* 108 */ 'l',
				/* 109 */ 'm',
				/* 110 */ 'n',
				/* 111 */ 'o',
				/* 112 */ 'p',
				/* 113 */ 'q',
				/* 114 */ 'r',
				/* 115 */ 's',
				/* 116 */ 't',
				/* 117 */ 'u',
				/* 118 */ 'v',
				/* 119 */ 'w',
				/* 120 */ 'x',
				/* 121 */ 'y',
				/* 122 */ 'z',
				/* 123 */ '{',
				/* 124 */ '|',
				/* 125 */ '}',
				/* 126 */ '~',
				/* 127 */ 8, //'\177',
				/* 128 */ ' ',
				/* 129 */ '\313',
				/* 130 */ '\347',
				/* 131 */ '\345',
				/* 132 */ '\314',
				/* 133 */ '\200',
				/* 134 */ '\201',
				/* 135 */ '\202',
				/* 136 */ '\351',
				/* 137 */ '\203',
				/* 138 */ '\346',
				/* 139 */ '\350',
				/* 140 */ '\355',
				/* 141 */ '\352',
				/* 142 */ '\353',
				/* 143 */ '\354',
				/* 144 */ ' ',
				/* 145 */ '\204',
				/* 146 */ '\361',
				/* 147 */ '\356',
				/* 148 */ '\357',
				/* 149 */ '\315',
				/* 150 */ '\205',
				/* 151 */ '\364',
				/* 152 */ '\362',
				/* 153 */ '\363',
				/* 154 */ '\206',
				/* 155 */ ' ',
				/* 156 */ ' ',
				/* 157 */ '\265',
				/* 158 */ ' ',
				/* 159 */ '\326',
				/* 160 */ '\251',
				/* 161 */ '\301',
				/* 162 */ '\242',
				/* 163 */ '\243',
				/* 164 */ '\332',
				/* 165 */ '\264',
				/* 166 */ '\304',
				/* 167 */ '\244',
				/* 168 */ '\333',
				/* 169 */ ' ',
				/* 170 */ '\322',
/*
				Mac		NeXT
	HOME		1
	END			4
	BACKSPACE	8
	PAGE-UP		11
	PAGE-DOWN	12
	ESCAPE		27
	LEFT-ARROW	28		172
	RIGHT-ARROW	29		174
	UP-ARROW	30		173
	DOWN-ARROW	31		175
	DELETE		127		127
	
*/
				/* 171 */ '\307',
				/* 172 */ 28, //'\334',
				/* 173 */ 30, //'\335',
				/* 174 */ 29, //'\336',
				/* 175 */ 31, //'\337',
				/* 176 */ '\250',
				/* 177 */ '\320',
				/* 178 */ '\240',
				/* 179 */ '\340',
				/* 180 */ '\341',
				/* 181 */ ' ',
				/* 182 */ '\246',
				/* 183 */ '\245',
				/* 184 */ '\342',
				/* 185 */ '\343',
				/* 186 */ '\323',
				/* 187 */ '\310',
				/* 188 */ '\311',
				/* 189 */ '\344',
				/* 190 */ '\302',
				/* 191 */ '\300',
				/* 192 */ ' ',
				/* 193 */ ' ',
				/* 194 */ '\253',
				/* 195 */ '\366',
				/* 196 */ '\367',
				/* 197 */ '\370',
				/* 198 */ '\371',
				/* 199 */ '\372',
				/* 200 */ '\254',
				/* 201 */ ' ',
				/* 202 */ '\373',
				/* 203 */ '\374',
				/* 204 */ ' ',
				/* 205 */ '\375',
				/* 206 */ '\376',
				/* 207 */ '\377',
				/* 208 */ '\321',
				/* 209 */ '\261',
				/* 210 */ ' ',
				/* 211 */ ' ',
				/* 212 */ ' ',
				/* 213 */ '\210',
				/* 214 */ '\207',
				/* 215 */ '\211',
				/* 216 */ '\213',
				/* 217 */ '\212',
				/* 218 */ '\214',
				/* 219 */ '\215',
				/* 220 */ '\217',
				/* 221 */ '\216',
				/* 222 */ '\220',
				/* 223 */ '\221',
				/* 224 */ '\223',
				/* 225 */ '\256',
				/* 226 */ '\222',
				/* 227 */ '\273',
				/* 228 */ '\224',
				/* 229 */ '\225',
				/* 230 */ ' ',
				/* 231 */ '\226',
				/* 232 */ ' ',
				/* 233 */ '\257',
				/* 234 */ '\316',
				/* 235 */ '\274',
				/* 236 */ '\230',
				/* 237 */ '\227',
				/* 238 */ '\231',
				/* 239 */ '\233',
				/* 240 */ '\232',
				/* 241 */ '\276',
				/* 242 */ '\235',
				/* 243 */ '\234',
				/* 244 */ '\236',
				/* 245 */ '\365',
				/* 246 */ '\237',
				/* 247 */ ' ',
				/* 248 */ ' ',
				/* 249 */ '\277',
				/* 250 */ '\317',
				/* 251 */ '\247',
				/* 252 */ ' ',
				/* 253 */ '\330',
				/* 254 */ ' ',
				/* 255 */ ' '
		};


	-(id)keyDown:(NXEvent*)event
	{
		int newtail=(keyTail+1)%KeyMax;
		eventFlags=(event->flags&0xffff0000)|(eventFlags&0x0000fffff);
		butBuffer[keyTail]=event->flags;
		keyBuffer[keyTail]=(0x0f00&((butBuffer[keyTail])>>9))
				|Conversion_next_to_macintosh[
					(unsigned char)(0xff&(event->data.key.charCode))];
#ifdef DEBUG_KEYDOWN
{unsigned char c=(unsigned char)(0xff&keyBuffer[keyTail]);
fprintf(stderr,"keydown: %c%c%c%c %c%c %3d \n",
	(butBuffer[keyTail]&(1<<20))?'M':' ',
	(butBuffer[keyTail]&(1<<19))?'O':' ',
	(butBuffer[keyTail]&(1<<18))?'C':' ',
	(butBuffer[keyTail]&(1<<17))?'S':' ',
	(c<' ')?'^':(c<128?' ':(c<128+32?'v':'_')),
	(c&0x7f)<32?((c&0x7f)+64):(c&0x7F),(int)c);
}
#endif
		if(interruptKeycode==keyBuffer[keyTail]){
			interruptPending=true;
			interruptCheckCounter=0;
		}else if(newtail!=keyHead){
			keyTail=newtail;
		}else{
			NXBeep();
		}
		return(self);
	}//keyDown:;


	-(BOOL)performKeyEquivalent:(NXEvent*)event
	{
		switch(event->data.key.charCode){
		case 'h':	// Command-h -> Hide.
		case 'q':	// Command-q -> Quit.
			return([super performKeyEquivalent:event]);
		default:
			[self keyDown:event];
			return(YES);
		}
	}//performKeyEquivalent:;
	
	
	-(void)redisplayAfterUnhide
	{
		//NOP.
	}//redisplayAfterUnhide;
	
	
	-(void)updateWholeDisplay
	{
		if(lastBitsIndex!=0){
			[self ioShowDisplayBitsIndex:lastBitsIndex 
					width:lastWidth height:lastHeight depth:lastDepth
					affectedLeft:0 affectedRight:lastWidth 
					affectedTop:0 affectedBottom:lastHeight];
		}
	}//updateWholeDisplay;
	

/* display,mouse,keyboard,time i/o */

	-(int)ioForceDisplayUpdate
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[[self window]flushWindow];
		NXPing();
		[NXApp ioProcessEvents];
		return(0);
	}//ioForceDisplayUpdate;
	
	
	-(int)ioFormPrintBitsAddr:(int)bAdr width:(int)w height:(int)h depth:(int)d 
			hScale:(double)hs vScale:(double)vs landscapeFlag:(int)lf
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];
#warning PJB: ioFormPrintBitsAddr Not implemented.			
		fprintf(stderr,"ioFormPrintBitsAddr:%x width:%d height:%d depth:%d\n"
				"              hScale:%f vScale:%f landscapeFlag:%d\n",
				bAdr,w,h,d,(float)hs,(float)vs,lf);
		return(0);
	}//ioFormPrintBitsAddr:;
	
	
	
	-(NXWindowDepth)screenDepth
	{
		const NXScreen* screen=[window screen];
		return(screen->depth);
	}//screenDepth;
	
	
	-(void)getScreenRect:(NXRect*)screenRect
	{
		const NXScreen* screen=[window screen];
		(*screenRect)=screen->screenBounds;
	}//getScreenRect:;
	
	
	-(int)ioSetFullScreen:(int)wantFullScreen
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];
		NX_DURING
			if(wantFullScreen!=isFullScreen){
				[NXApp prepareFullScreen:wantFullScreen 
						noTitle:[[NXApp preferences]noTitle]];
				isFullScreen=wantFullScreen;
			}
#if 0
			if(wantFullScreen&&(!isFullScreen)){
				/* setting full-screen mode */
				NXRect fsRect;
				PScurrentwindowlevel([window windowNum],&savedLevel);
				[window getFrame:&savedWindowPlace andScreen:&savedScreen];
				fsRect.origin.x=savedScreen->screenBounds.origin.x-1;
				fsRect.origin.y=savedScreen->screenBounds.origin.y-11;
				fsRect.size.width=savedScreen->screenBounds.size.width+1;
				fsRect.size.height=savedScreen->screenBounds.size.height+31;
				[self windowWillResize:self toSize:&(fsRect.size)];
				PSsetwindowlevel(NX_SUBMENULEVEL-1,[window windowNum]);
				[window placeWindow:&fsRect];
				[window sizeWindow:fsRect.size.width:fsRect.size.height];
				isFullScreen=YES;
			}else if((!wantFullScreen)&&isFullScreen){
				/* reverting to sub-screen mode */
				PSsetwindowlevel(savedLevel,[window windowNum]);
				[window placeWindow:&savedWindowPlace screen:savedScreen];
				isFullScreen=NO;
			}
#endif
		NX_HANDLER
			fprintf(stderr,"An exception is caught in [%s %s]: "
					"code=%d data1=0x%x data2=0x%x\n",
					"SqView",sel_getName(_cmd),NXLocalHandler.code,
					(unsigned int)NXLocalHandler.data1,
					(unsigned int)NXLocalHandler.data2);
		NX_ENDHANDLER
		return(0);
	}//ioSetFullScreen:;
	



	-(int)ioGetButtonState
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];
		return(buttonState);
	}//ioGetButtonState;
	
	
	-(int)ioMousePoint
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		NXPoint			mouse;
		int             x;
		int             y;
		[NXApp ioProcessEvents];
		NX_DURING
			PScurrentmouse([window windowNum],&(mouse.x),&(mouse.y));
			[self convertPoint:&mouse fromView:NIL];
			[self point:&mouse toSq:&x:&y];
		NX_HANDLER
			fprintf(stderr,"An exception is caught in [%s %s]: "
					"code=%d data1=0x%x data2=0x%x\n",
					"SqView",sel_getName(_cmd),NXLocalHandler.code,
					(unsigned int)NXLocalHandler.data1,
					(unsigned int)NXLocalHandler.data2);
		NX_ENDHANDLER
		return(((x&0xffff)<<16)|(y&0xffff));
	}//ioMousePoint;
	
	
	
	
	-(int)ioPeekKeystroke
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];

		if(keyHead==keyTail){
			return(-1);
		}else{
			[self updateButtonStateWith:butBuffer[keyHead]];
			return(keyBuffer[keyHead]);
		}
	}//ioPeekKeystroke;
	
	
	
	-(int)ioGetKeystroke
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];
		
		if(keyHead==keyTail){
			return(-1);
		}else{
			int result=keyBuffer[keyHead];
			[self updateButtonStateWith:butBuffer[keyHead]];
			keyHead=(keyHead+1)%KeyMax;
			return(result);
		}
	}//ioGetKeystroke;
	
	
	
	-(int)ioScreenSize
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		[NXApp ioProcessEvents];
		/* width is high 16 bits; height is low 16 bits */
 		return(((((int)bounds.size.width)&0xffff)<<16)
				|(((int)bounds.size.height)&0xffff));
	}//ioScreenSize;
	
	


	-(int)ioSetCursorBitsIndex:(int)cursorBitsIndex 
			withMask:(int)cursorMaskIndex
			offsetX:(int)x offsetY:(int)y
	{
		return([self ioSetCursorBitsIndex:cursorBitsIndex 
				offsetX:x offsetY:y]);
	}//ioSetCursorBitsIndex:withMask:offsetX:offsetY:;


	-(int)ioSetCursorBitsIndex:(int)cursorBitsIndex 
			offsetX:(int)x offsetY:(int)y
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		NXImage*            image;
		NXBitmapImageRep*   bitmap;
		NXPoint             hotSpot={-x,-y};
		unsigned char*      data;
		unsigned char*      mask;
		unsigned char*      planes[5];
		int                 i;

		NX_DURING
			bitmap=[[NXBitmapImageRep alloc] initDataPlanes:0 
					pixelsWide:16
					pixelsHigh:16
					bitsPerSample:1
					samplesPerPixel:2
					hasAlpha:YES
					isPlanar:YES
					colorSpace:NX_OneIsBlackColorSpace
					bytesPerRow:2
					bitsPerPixel:0];
			[bitmap getDataPlanes:planes];
			data=planes[0];
			mask=planes[1];
			
			for(i=0;i<16;i++){
				unsigned int chunk;
				chunk=(unsigned)checkedLongAt(cursorBitsIndex+(4*i));
				data[i*2+0]=(chunk>>24)&0xFF;
				data[i*2+1]=(chunk>>16)&0xFF;
				mask[i*2+0]=(~(data[i*2+0]));
				mask[i*2+1]=(~(data[i*2+1]));
			}
			
			if(cursor==0){
				image=[[NXImage alloc]init];
				[image useRepresentation:bitmap];
				cursor=[[NXCursor alloc]initFromImage:image];
				[cursor setHotSpot:&hotSpot];
				[cursor set];
				// You must not free image since it is not copied by the
				// cursor. It only keep a reference to the images.
			}else{
				BOOL cursorIsCurrent=[NXCursor currentCursor]==cursor;
				image=[cursor image];
				if(cursorIsCurrent){
					[transparentCursor push];
				}
				[image removeRepresentation:[image lastRepresentation]];
				[image useRepresentation:bitmap];
				[cursor setImage:image];
				[cursor setHotSpot:&hotSpot];
				if(cursorIsCurrent){
					[NXCursor pop];
				}
				[cursor set];				
			}
		NX_HANDLER
			fprintf(stderr,"An exception is caught in [%s %s]: "
					"code=%d data1=0x%x data2=0x%x\n",
					"SqView",sel_getName(_cmd),NXLocalHandler.code,
					(unsigned int)NXLocalHandler.data1,
					(unsigned int)NXLocalHandler.data2);
		NX_ENDHANDLER
		return(0);
	}//ioSetCursorBitsIndex:offsetX:offsetY:;


	-(int)ioShowDisplayBitsIndex:(int)bitsIndex 
			width:(int)width height:(int)height depth:(int)depth 
			affectedLeft:(int)left affectedRight:(int)right 
			affectedTop:(int)top affectedBottom:(int)bottom
	{
		debug(int dummy=fprintf(stderr,"%s\n",sel_getName(_cmd));\
			int fummy=fflush(stderr);)
		debug(int dumm2=fprintf(stderr,"%22x%6d%7d%6d%13d%14d%12d%15d\n",\
			bitsIndex,width,height,depth,\
			left,right,top,bottom);)
		NXBitmapImageRep* bitmap=0;

		if((right<=left)||(bottom<=top)){
			return(1);
		}
		
		// This can happen after resizing the window:
		if(width<right){
			right=width;
		}
		if(height<bottom){
			bottom=height;
		}

		lastBitsIndex=bitsIndex;
		lastWidth=width;
		lastHeight=height;
		lastDepth=depth;
		
		NX_DURING
			debug(fprintf(stderr,"[SqView 0x%08x canDraw]=%d\n",
					(int)self,[self canDraw]);)
			if([self canDraw]){
				NXPoint position;
				
				[self lockFocus];
				if(![self isFocusView]){
					fprintf(stderr,"ASSERT ERROR: ![self isFocusView]\n");
				}
				
				bitmap=[self computeBitmapFromBitsIndex:(void*)bitsIndex
						width:width height:height depth:depth 
						left:left right:right top:top bottom:bottom
						position:&position];
				[bitmap drawAt:&position];
				free([bitmap data]);
				[bitmap free];
				
				[[self window]flushWindow];  // Could wait?
				NXPing();                    // Could wait?
				[self unlockFocus];
			}
			debug(fprintf(stderr,"SqView done.\n");)
		NX_HANDLER
			fprintf(stderr,"An exception is caught in [%s %s]: "
					"code=%d data1=0x%x data2=0x%x\n",
					"SqView",sel_getName(_cmd),NXLocalHandler.code,
					(unsigned int)NXLocalHandler.data1,
					(unsigned int)NXLocalHandler.data2);
			if([self isFocusView]){
				[[self window]flushWindow];  // Could wait?
				NXPing();                    // Could wait?
				[self unlockFocus];
			}
			if(bitmap!=0){
				[bitmap free];
				bitmap=0;
			}
		NX_ENDHANDLER
		return(0);
	}//ioShowDisplayBitsIndex:width:height:depth:affectedLeft:...;


@end // SqView.

/*** SqView.m / Thu Aug 27 23:21:05 MET 1998 / PJB ***/
