ImagerStdColorDisplayImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Frank Crow, June 15, 1984 2:28:59 pm PDT
DIRECTORY
Imager    USING [XOR, Error],
ImagerBasic   USING [DeviceRectangle, Color, ColorRep, IntRectangle],
ImagerDisplay  USING [DisplayClass, DisplayClassRep, DisplayData, DisplayDataRep],
ImagerMasks   USING [Mask, ApplyConstant, BoundingBox],
ImagerPixelMaps  USING [PixelMap, PixelMapRep, Fill, Function],
ColorModels   USING [Calibration, GetPhosphorCalibration],
ConstantColors  USING [RGBToColor, white],
Terminal    USING [ColorMode, ChannelsVisible, Current, GetColorMode, Virtual,
         WaitForBWVerticalRetrace],
TerminalExtras  USING [LockColorFrame, UnlockColorFrame],
TerminalColorExtras USING [SetColorBitmapState],
Interminal   USING [TurnOnColorCursor, TurnOffColorCursor],
Basics     USING [bitsPerWord, LongMult, BITSHIFT],
Atom     USING [MakeAtom, PutPropOnList, GetPropFromList],
WindowManager USING [ScreenPos, StopColorViewers, StartColorViewers],
ColorDisplayFaceExtras USING [DisplayType, SetMonitorType, SetBOffsets, SwitchChannels],
CountedVM   USING [Allocate, Pointer, Handle],
UserProfile   USING [Token, ProfileChangedProc, CallWhenProfileChanges],
Rope     USING [ROPE, Equal],
ImagerStdColorDisplay;
ImagerStdColorDisplayImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerMasks, ColorModels, ConstantColors, Terminal, TerminalExtras,
   TerminalColorExtras, Atom, UserProfile, Rope, CountedVM, Basics, Interminal,
   ColorDisplayFaceExtras, ImagerPixelMaps, WindowManager
EXPORTS ImagerStdColorDisplay
~ BEGIN
This provides support for the Dorado color display hardware common to standard displays.
DisplayClass: TYPE ~ ImagerDisplay.DisplayClass;
DisplayClassRep: TYPE ~ ImagerDisplay.DisplayClassRep;
DisplayData: TYPE ~ ImagerDisplay.DisplayData;
DisplayDataRep: TYPE ~ ImagerDisplay.DisplayDataRep;
DeviceRectangle: TYPE ~ ImagerBasic.DeviceRectangle;
Color: TYPE ~ ImagerBasic.Color;
ColorRep: TYPE ~ ImagerBasic.ColorRep;
SampledColor: TYPE = REF ColorRep.sampled;
ConstantColor: TYPE = REF ColorRep.constant;
SpecialColor: TYPE = REF ColorRep.special;
Mask: TYPE ~ ImagerMasks.Mask;
ColorDisplayError: PUBLIC SIGNAL [reason: ATOM] ~ CODE;
pixelsPerInch: NAT;
monitorType: ColorDisplayFaceExtras.DisplayType;
currentDisplay: DisplayData ← NIL;        -- Currently displayed context
displaySide: WindowManager.ScreenPos;
colorCalibration: PUBLIC ColorModels.Calibration;
Create: PUBLIC PROC [vt: Terminal.Virtual, mode: Terminal.ColorMode,
       displayClass: DisplayClass, creationData: REF,
       bitsPerPixel: NAT, setUpMapProc: ImagerStdColorDisplay.SetUpMapProc]
  RETURNS [displayData: DisplayData] ~ {
The creationData is inherited from the Create call. Here it is used to specify the dimensions of the pixel map and whether or not to pin it to the screen. NIL, defaults to using the hardware's display dimensions and pinning immediately.
GetPixelMap: PROC [x, y, width, height, bitsPerPixel: NAT,
       pointer: LONG POINTER ← NIL]
     RETURNS[pixelMap: ImagerPixelMaps.PixelMap] ~ {
lgBitsPerPixel: NAT;
words: INT;
storage: CountedVM.Handle ← NIL;
wordsPerLineA: INT ← width * MIN[ bitsPerPixel,
           IF mode.full THEN 16 ELSE mode.bitsPerPixelChannelA];
wordsPerLineB: INTIF bitsPerPixel > mode.bitsPerPixelChannelA
THEN width * mode.bitsPerPixelChannelB ELSE 0;
IF wordsPerLineA MOD Basics.bitsPerWord # 0
THEN wordsPerLineA ← wordsPerLineA/ Basics.bitsPerWord + 1
ELSE wordsPerLineA ← wordsPerLineA/ Basics.bitsPerWord;
IF wordsPerLineB MOD Basics.bitsPerWord # 0
THEN wordsPerLineB ← wordsPerLineB/ Basics.bitsPerWord + 1
ELSE wordsPerLineB ← wordsPerLineB/ Basics.bitsPerWord;
Words to allocate: add 8 pages for maps, etc. needed by color display
words ← Basics.LongMult[wordsPerLineA + wordsPerLineB, height + 1] + 2048;
IF mode.full THEN words ← words + 512;    -- extra space for extra color tables
IF pointer = NIL THEN {
storage ← CountedVM.Allocate[words: words];
TRUSTED { pointer ← CountedVM.Pointer[storage]; };
};
IF bitsPerPixel > mode.bitsPerPixelChannelA AND ~mode.full
THEN bitsPerPixel ← mode.bitsPerPixelChannelA;
SELECT bitsPerPixel FROM    -- log bits per pixel for first map
1    => lgBitsPerPixel ← 0;
2    => lgBitsPerPixel ← 1;
4    => lgBitsPerPixel ← 2;
8     => lgBitsPerPixel ← 3;
16,24,32   => lgBitsPerPixel ← 4;
ENDCASE  => ColorDisplayError[$BitsPerPixelWrong];
pixelMap [
sOrigin: y, fOrigin: x, sMin: 0, fMin: 0,
sSize: height,
fSize: width,
refRep: NEW [ImagerPixelMaps.PixelMapRep ← [
ref: storage,
pointer: pointer,
words: words,
lgBitsPerPixel: lgBitsPerPixel,
rast: wordsPerLineA,
lines: height
]]
];
ImagerPixelMaps.Fill[ pixelMap, [0, 0, height, width], Basics.BITSHIFT[1, bitsPerPixel] - 1 ]
};
numMaps: NAT;
channelsVisible: Terminal.ChannelsVisible;
colorData: REF ImagerStdColorDisplay.ColorMapData;
creationList: LIST OF REF ANYNARROW[creationData, LIST OF REF ANY];
adjPixPerInch: NATIF monitorType = conrac7211Hi AND mode.full
THEN pixelsPerInch/2 ELSE pixelsPerInch;
SELECT bitsPerPixel FROM
1,2,4,6,10 => numMaps ← 1;
16,24   => numMaps ← 2;
32   => numMaps ← 4;
ENDCASE => ColorDisplayError[$BitsPerPixelWrong];
channelsVisible ← IF bitsPerPixel > 16 THEN all ELSE aOnly;
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
WindowManager.StopColorViewers[];  -- !!!!! this should be done when terminalimpl is fixed
IF creationList = NIL THEN {      -- use default pixel map
displayData ← NEW[DisplayDataRep[numMaps]];  -- Make a rep
Get display set up and turned on
IF mode.bitsPerPixelChannelB < 8 THEN { -- no overlays here
mode.bitsPerPixelChannelB ← 0; bitsPerPixel ← mode.bitsPerPixelChannelA; };
[] ← TerminalColorExtras.SetColorBitmapState[vt, displayed, mode, channelsVisible];
displayData[0] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, bitsPerPixel,
         vt.colorBitmapA]; -- gets up to 24 bits per pixel from Terminal
IF currentDisplay # NIL THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← displayData;
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $Displayed];
IF mode.full THEN {       -- full color, set up multiple pixel maps
blueMap: NATIF numMaps = 4 THEN 2 ELSE 1;   -- position of Blue map in sequence
displayData[blueMap] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8,
           vt.colorBitmapB];
IF numMaps = 4 THEN {
displayData[1] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8]; -- green pixels
displayData[3] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight, 8]; -- alpha pixels
};
}
ELSE IF numMaps = 2 THEN    -- second pixel map used as overlay or double buffer
displayData[1] ← GetPixelMap[0, 0, vt.colorWidth, vt.colorHeight,
         bitsPerPixel - mode.bitsPerPixelChannelA, vt.colorBitmapB];
}
ELSE {         -- Non-nil creation list, build new pixel map
pinned: BOOLEANTRUE;
box, box2: REF ImagerBasic.IntRectangle ← NIL;
nullBox: ImagerBasic.IntRectangle ← [0, 0, 0, 0];
WHILE creationList # NIL DO       -- pick up pin command, box, or both
WITH creationList.first SELECT FROM
pinTruth: REF BOOLEAN => pinned ← pinTruth^;  -- Display now or just compute?
boxRef: REF ImagerBasic.IntRectangle => IF box = NIL
THEN box ← boxRef       -- For less than the full screen
ELSE box2 ← boxRef;      -- For overlays (both boxes needed)
ENDCASE;
creationList ← creationList.rest
ENDLOOP; 
IF box = NIL THEN box^ ← [0, 0, vt.colorWidth, vt.colorHeight];  -- use screen size
IF box2 # NIL AND numMaps = 1
THEN numMaps ← 2   -- an overlay map needed
ELSE IF numMaps = 1 THEN {
bitsPerPixel ← mode.bitsPerPixelChannelA;
mode.bitsPerPixelChannelB ← 0; };
displayData ← NEW[DisplayDataRep[numMaps]];  -- Make a rep
displayData[0] ← GetPixelMap[box.x, box.y, box.w, box.h, bitsPerPixel]; -- gets up to 24 bpp
IF mode.full THEN {       -- full color, set up multiple pixel maps
IF numMaps > 1 THEN {
blueMap: NATIF numMaps = 4 THEN 2 ELSE 1;
blueBits: LONG POINTER;   -- blue pixels lie above 16-bit interleaved RG pixels
TRUSTED {
blueBits ← displayData[0].refRep.pointer
   + Basics.LongMult[displayData[0].refRep.rast, box.h]
};
displayData[blueMap] ← GetPixelMap[box.x, box.y, box.w, box.h, 8, blueBits];
IF numMaps = 4 THEN {
displayData[1] ← GetPixelMap[box.x, box.y, box.w, box.h, 8];  -- green pixels
displayData[3] ← GetPixelMap[box.x, box.y, box.w, box.h, 8];  -- alpha pixels
};
};
}
ELSE IF numMaps = 2 THEN {   -- overlay or double buffer
mapBits: LONG POINTER;
TRUSTED {
mapBits ← displayData[0].refRep.pointer
   + Basics.LongMult[displayData[0].refRep.rast, box.h]
};
IF box2 = NIL THEN box2 ← box;
displayData[1] ← GetPixelMap[box2.x, box2.y, box2.w, box2.h,
         bitsPerPixel - mode.bitsPerPixelChannelA, mapBits];
};
IF pinned            -- point display at bits
THEN {
IF box2 = NIL THEN { box2 ← box; mode.bitsPerPixelChannelB ← 0; }; -- single map
[] ← TerminalColorExtras.SetColorBitmapState[
vt, displayed, mode, channelsVisible,
box.w, box.h, box2.w, box2.h,
NARROW[displayData[0].refRep.ref, CountedVM.Handle].interval
];
IF currentDisplay # NIL THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← displayData;
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus,$Displayed];
}
ELSE
displayData.props ← Atom.PutPropOnList[displayData.props, $PixelMapStatus, $Allocated];
};
IF bitsPerPixel < 16 AND numMaps = 2 THEN {
channelsVisible ← all;
[] ← TerminalColorExtras.SetColorBitmapState[vt, displayed, mode, channelsVisible];
};
IF currentDisplay # NIL THEN TRUSTED {
Interminal.TurnOnColorCursor[        -- turn on cursor
IF mode.full THEN 24 ELSE mode.bitsPerPixelChannelA,     -- bits per pixel
displaySide = left               -- true => on left
]; };
WindowManager.StartColorViewers[displaySide, mode.bitsPerPixelChannelA]; -- problems!!!??
displayData.displayClass ← displayClass;
Pixels/inch. Depends on display size and # of lines, from User.Profile in Init[]
displayData.xRes ← adjPixPerInch * displayClass.viewUnitsPerPixel;
displayData.yRes ← adjPixPerInch * displayClass.viewUnitsPerPixel;
displayData.rotate ← TRUE;
displayData.cachedColor ← NIL;
colorData ← NEW[ImagerStdColorDisplay.ColorMapData];
colorData.pixelValueList ← NIL;
colorData.colorCalibration ← colorCalibration;
colorData.nextEntry ← 0;
colorData.map ← NIL;
displayData.cachedColorData ← colorData;
setUpMapProc[displayData];
displayData.surfaceWidth ← displayData[0].fSize * displayClass.viewUnitsPerPixel;
displayData.surfaceHeight ← displayData[0].sSize * displayClass.viewUnitsPerPixel;
};
PinPixelMap: PUBLIC PROC [vt: Terminal.Virtual, data: DisplayData, mode: Terminal.ColorMode] ~ {
Pin a pixel map to the color display, replacing whatever was there before.
fSize2, sSize2: NAT;
channelsVisible: Terminal.ChannelsVisible ←
IF data.numberOfSeparations > 1 AND (mode.bitsPerPixelChannelB # 8 OR mode.full)
THEN all ELSE aOnly;
IF data[0].refRep.ref = NIL THEN ColorDisplayError[$ContextDoesntOwnPixelMap];
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
IF channelsVisible = all THEN { fSize2 ← data[1].fSize; sSize2 ← data[1].sSize; }
        ELSE { fSize2 ← data[0].fSize; sSize2 ← data[0].sSize; };
[] ← TerminalColorExtras.SetColorBitmapState[
vt, displayed, mode, channelsVisible,
data[0].fSize, data[0].sSize, fSize2, sSize2,
NARROW[data[0].refRep.ref, CountedVM.Handle].interval
];
IF currentDisplay # NIL THEN currentDisplay.props ←
Atom.PutPropOnList[ currentDisplay.props, $PixelMapStatus, $Allocated ];
currentDisplay ← data;
data.props ← Atom.PutPropOnList[ data.props, $PixelMapStatus,$Displayed];
IF currentDisplay # NIL THEN TRUSTED {
Interminal.TurnOnColorCursor[        -- turn on cursor
IF mode.full THEN 24 ELSE mode.bitsPerPixelChannelA,     -- bits per pixel
displaySide = left               -- true => on left
]; };
};
ReleasePixelMap: PUBLIC PROC [vt: Terminal.Virtual, data: DisplayData] ~ {
Remove a pixel map from the color display
IF data # currentDisplay THEN Imager.Error[$DataNotCurrentDisplay];
TRUSTED { Interminal.TurnOffColorCursor[]; }; -- for safety's sake, disallow cursor action
[] ← TerminalColorExtras.SetColorBitmapState[
vt, allocated, Terminal.GetColorMode[vt], none,
];
data.props ← Atom.PutPropOnList[ data.props, $PixelMapStatus, $Allocated ];
currentDisplay ← NIL;
};
MoveOverlay: PUBLIC PROC [vt: Terminal.Virtual, data: REF ANY] ~ {
x, y: NAT ← 0;
list: LIST OF REF ANYNARROW[data, LIST OF REF ANY];
x ← NARROW[list.first, REF INTEGER]^;
list ← list.rest;
y ← NARROW[list.first, REF INTEGER]^;
TRUSTED { ColorDisplayFaceExtras.SetBOffsets[x, y]; };
};
SwitchBuffers: PUBLIC PROC [] ~ {
TRUSTED { ColorDisplayFaceExtras.SwitchChannels[]; };
};
DoUnderLock: PUBLIC PROC [displayData: DisplayData, action: PROC, rectangle: DeviceRectangle] ~ {
vt: Terminal.Virtual ← Terminal.Current[];
TerminalExtras.LockColorFrame[
vt: vt,
xmin: MAX[rectangle.fMin, 0],
ymin: MAX[rectangle.sMin, 0],
xmax: MAX[rectangle.fMin+rectangle.fSize, 0],
ymax: MAX[rectangle.sMin+rectangle.sSize, 0]
];
action[! UNWIND => {TerminalExtras.UnlockColorFrame[vt]}];
TerminalExtras.UnlockColorFrame[vt];
};
ApplyMask: PUBLIC PROC [displayData: DisplayData,
         color: Color, mask: Mask, sTranslate, fTranslate: INTEGER,
         cachedColorProc: ImagerStdColorDisplay.CachedColorProc] ~ {
LockedApplyMask: PROC ~ {
function: ImagerPixelMaps.Function ← [null, null];
IF color = Imager.XOR THEN {
color ← ConstantColors.white;
function ← [xor, null];
};
WITH color SELECT FROM
constantColor: ConstantColor => {
ImagerMasks.ApplyConstant[
mask: mask,
clipper: displayData.compositeClipper,
dest: displayData[separationNumber],
value: currentPixelValue,
function: function,
sTranslate: sTranslate,
fTranslate: fTranslate
];
};
ENDCASE => Imager.Error[$UnsupportedColorType];
};
separationNumber: NAT;
pixelValues: LIST OF CARDINAL;
currentPixelValue: CARDINAL;
colorData: REF ImagerStdColorDisplay.ColorMapData ← NARROW[displayData.cachedColorData];
bb: DeviceRectangle ← ImagerMasks.BoundingBox[mask];
bb.sMin ← bb.sMin + sTranslate;
bb.fMin ← bb.fMin + fTranslate;
IF color # displayData.cachedColor THEN cachedColorProc[displayData, color];
pixelValuescolorData.pixelValueList;
FOR separationNumber IN [0..displayData.numberOfSeparations) DO IF pixelValues # NIL
THEN {
currentPixelValue ← pixelValues.first; pixelValues ← pixelValues.rest;
IF Atom.GetPropFromList[displayData.props, $PixelMapStatus] = $Displayed THEN
DoUnderLock[displayData, LockedApplyMask, bb]
ELSE LockedApplyMask[];
};
ENDLOOP;
};
LoadColorMap: PUBLIC PROC [ vt: Terminal.Virtual, data: REF ANY,
          displayData: DisplayData,
          loadColor: ImagerStdColorDisplay.LoadColorProc] ~ {
start: NAT ← 0;
rgbEntries: REF ImagerStdColorDisplay.RGBSequence ← NIL;
colorEntries: REF ImagerStdColorDisplay.ColorSequence ← NIL;
colorData: REF ImagerStdColorDisplay.ColorMapData ← NIL;
oldColorData: REF ImagerStdColorDisplay.ColorMapData ← NARROW[displayData.cachedColorData];
colorCalibration: ColorModels.Calibration ← oldColorData.colorCalibration;
list: LIST OF REF ANYNARROW[data, LIST OF REF ANY];
mode: Terminal.ColorMode ← vt.GetColorMode;
vt.WaitForBWVerticalRetrace[]; -- await vt selection and top of scan (to control update rate)
WHILE list # NIL DO
WITH list.first SELECT FROM  -- pick up map description
rgb: REF ImagerStdColorDisplay.RGBSequence => rgbEntries ← rgb;
color: REF ImagerStdColorDisplay.ColorSequence => colorEntries ← color;
colorMap: REF ImagerStdColorDisplay.ColorMapData => colorData ← colorMap;
calibration: ColorModels.Calibration => colorCalibration ← calibration;
nat: REF INTEGER => start ← nat^;
ENDCASE;
list ← list.rest;
ENDLOOP;
IF colorData # NIL THEN { colorEntries ← colorData.map; oldColorData ← colorData; };
IF rgbEntries = NIL AND colorEntries # NIL THEN {
FOR i: NAT IN [0..MAX[colorEntries.length, 256]) DO
oldColorData.map[i] ← colorEntries[i];
loadColor[ colorEntries[i], colorCalibration, i ];
ENDLOOP;
oldColorData.nextEntry ← colorEntries.length;
};
IF rgbEntries # NIL THEN {
FOR i: NAT IN [0..MAX[rgbEntries.length, 256]) DO
oldColorData.map[i] ← ConstantColors.RGBToColor[
       rgbEntries[i].r/255.0, rgbEntries[i].g/255.0, rgbEntries[i].b/255.0,
       colorCalibration ];
loadColor[ oldColorData.map[i], colorCalibration, i ];
ENDLOOP;
oldColorData.nextEntry ← rgbEntries.length;
};
};
MonitorSpecs: UserProfile.ProfileChangedProc = TRUSTED {
Initialize: set left margin assuming monitor type from resolution (potentially wrong)
displayType: Rope.ROPE ← UserProfile.Token["ColorDisplay.Type", "conrac7211Lo"];
SELECT TRUE FROM
Rope.Equal[displayType, "ramtek714", FALSE] => { monitorType ← ramtek714;
                pixelsPerInch ← 64;   };
Rope.Equal[displayType, "Hitachi2713", FALSE] => { monitorType ← hitachi2713;
                pixelsPerInch ← 64;   };
Rope.Equal[displayType, "conrac7211Lo", FALSE] => { monitorType ← conrac7211Lo;
                pixelsPerInch ← 42;   };
Rope.Equal[displayType, "conrac7211Hi", FALSE] => { monitorType ← conrac7211Hi;
                pixelsPerInch ← 68;   };
ENDCASE => Imager.Error[$UnknownDisplayType];
IF monitorType = conrac7211Hi
THEN ColorDisplayFaceExtras.SetMonitorType[monitorType, 1024, 768]
ELSE ColorDisplayFaceExtras.SetMonitorType[monitorType, 640, 480];
Get display parameters (height, width, etc.) registered in Terminal's global variables
[] ← TerminalColorExtras.SetColorBitmapState[Terminal.Current[], allocated, [FALSE, 1, 0], none];
displaySide ← IF Rope.Equal[UserProfile.Token["ColorDisplay.Side", "left"], "left", FALSE]
THEN left ELSE right;
colorCalibration ← ColorModels.GetPhosphorCalibration[
Atom.MakeAtom[UserProfile.Token["ColorDisplay.Calibration", "DefaultLP"] ]
];
};
{
UserProfile.CallWhenProfileChanges[MonitorSpecs];
};
END.