ColorDisplayImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Tim Diebert: May 20, 1986 10:56:50 am PDT
Bloomenthal, August 15, 1986 2:29:47 pm PDT
Last edited by: Mik Lamming - July 30, 1986 5:43:04 pm PDT
DIRECTORY
Ascii USING [Lower],
Buttons USING [Button, ButtonProc, Create, SetDisplayStyle],
ColorDisplay USING [CDNotifyProc, CDRegistration, CDState],
ColorDisplayDefs USING [colorMode24, ColorDisplayType, ColorMode],
ColorDisplayFace USING [SetDisplayType],
Commander USING [CommandProc, Register],
Containers USING [Container, Create],
Imager, ImagerDevice, ImagerTerminal, InterminalBackdoor, ImagerCache, ImagerRaster, ImagerColorMap,
ImagerColor USING [ColorFromGray],
ImagerForkContext USING [Create],
ImagerGray USING [Create, LikeScreen],
ImagerMaskContext USING [Create],
ImagerPixelMap USING [PixelMap, PixelMapRep],
Interminal USING [GetColorDisplaySide, SetColorDisplaySide],
IO USING [card, EndOfStream, GetTokenRope, IDProc, PutF, RIS, rope, STREAM],
MessageWindow USING [Append, Blink],
Process USING [Detach, Pause, SetTimeout, Ticks],
Rope USING [Equal, Fetch, Length, ROPE, Translate, TranslatorType],
SafeStorage USING [ReclaimCollectibleObjects],
Terminal USING [BitmapState, CantDoIt, ChannelsVisible, ColorMode, Current, FrameBuffer, GetColorBitmapState, GetColorMode, GetColorFrameBufferA, GetColorFrameBufferB, GetVisibility, SetColorBitmapState, SetColorCursorPresentation, SetColorMode, Virtual],
UserProfile USING [Boolean, Number, Token],
ViewerClasses USING [Viewer],
ViewerOps USING [ChangeColumn, CloseViewer, ComputeColumn, EnumerateViewers, EnumProc, OpenIcon, PaintEverything, SetOpenHeight],
ViewerPrivate USING [Screen, SetCreator],
WindowManager USING [colorDisplayOn, ScreenPos, StartColorViewers, StopColorViewers];
ColorDisplayImpl: CEDAR MONITOR
IMPORTS Ascii, Buttons, ColorDisplayFace, Commander, Containers, ImagerCache, ImagerColor, ImagerColorMap, ImagerForkContext, ImagerGray, ImagerMaskContext, ImagerRaster, ImagerTerminal, Interminal, InterminalBackdoor, IO, MessageWindow, Process, Rope, SafeStorage, Terminal, UserProfile, ViewerOps, ViewerPrivate, WindowManager
EXPORTS ColorDisplay
~ BEGIN OPEN ColorDisplay;
bppLast and sideLast are examined only when the color display is off. This lets the ColorDisplay package know where to default them to when the color display is turned on again. NOTE: Every call to the ColorDisplay package will cause these values to be updated with the actual state of the machine, if it is on.
bppLast: PUBLIC CARDINAL ← 8;
bppBLast: PUBLIC CARDINAL ← 0;
onLeftLast: PUBLIC BOOLEANTRUE;
grayLast: PUBLIC BOOLEANFALSE;
monitorTypeLast: PUBLIC Rope.ROPE ← "640x480";
DefaultBpp, Bpp: PUBLIC PROC RETURNS [bpp: CARDINAL] ~ { -- remembers bpp
IF WindowManager.colorDisplayOn
THEN {
OPEN Terminal;
colorMode: ColorMode ← GetColorMode[Current[]];
bpp ← (IF colorMode.full THEN 24 ELSE colorMode.bitsPerPixelChannelA);
}
ELSE bpp ← bppLast;
bppLast ← bpp; --Remember the setting of the screen
};
DefaultBppB, BppB: PUBLIC PROC RETURNS [bpp: CARDINAL] ~ { -- remembers bpp
IF WindowManager.colorDisplayOn
THEN {
OPEN Terminal;
colorMode: ColorMode ← GetColorMode[Current[]];
bpp ← (IF colorMode.full THEN 0 ELSE colorMode.bitsPerPixelChannelB);
}
ELSE bpp ← bppBLast;
bppBLast ← bpp; --Remember the setting of the screen
};
DefaultOnLeft, OnLeft: PUBLIC PROC RETURNS [onLeft: BOOLEAN] ~ {
onLeft ← IF WindowManager.colorDisplayOn
THEN Interminal.GetColorDisplaySide[] = left ELSE onLeftLast;
onLeftLast ← onLeft;
};
DefaultGray, Gray: PUBLIC PROC RETURNS [onLeft: BOOLEAN] ~ {
RETURN[grayLast];
};
DefaultOn: PUBLIC PROC RETURNS [BOOLEAN] ~ {
RETURN[WindowManager.colorDisplayOn];
};
DefaultMonitorType: PUBLIC PROC RETURNS [Rope.ROPE] ~ {
RETURN[monitorTypeLast];
};
MessageBlink: PROC [message: Rope.ROPE] ~ {
MessageWindow.Append[message, TRUE];
MessageWindow.Blink[];
};
SetColorDisplayStatus: PUBLIC ENTRY PROC [on: BOOLEAN ← DefaultOn[],
onLeft: BOOLEAN ← DefaultOnLeft[], gray: BOOL ← DefaultGray[],
bpp: CARDINAL ← DefaultBpp[], bppB: CARDINAL ← DefaultBppB[], monitorType: Rope.ROPE ← DefaultMonitorType[]] = {
ENABLE UNWIND => NULL;
NOTIFY forCDChanges;  --Let the informant know...
IF NOT InterminalBackdoor.terminal.hasColorDisplay THEN RETURN; -- No color display.
SELECT bpp FROM
1, 2, 4, 8, 24 => NULL;
ENDCASE => {MessageBlink["Invalid bits per pixel."];
RETURN};
SELECT bppB FROM
0, 1, 2 => NULL;
ENDCASE => {MessageBlink["Invalid bits per pixel on chan B."];
RETURN};
IF NOT (Rope.Equal[s1: monitorType, s2: "640x480", case: FALSE]
OR Rope.Equal[s1: monitorType, s2: "1024x768", case: FALSE]) THEN {
MessageBlink["Invalid monitor type."];
RETURN};
SELECT TRUE FROM
Check for nothing changed
(on = WindowManager.colorDisplayOn
AND bpp = Bpp[]
AND bppB = BppB[]
AND Rope.Equal[monitorType, monitorTypeLast, FALSE]
AND onLeft=OnLeft[]
AND gray=Gray[]) => RETURN;
Check for change in gray in 8 bpp
(on = WindowManager.colorDisplayOn
AND Rope.Equal[monitorType, monitorTypeLast, FALSE]
AND Bpp[] = bpp
AND gray # Gray[]
AND on) => {IF Gray[] THEN DefaultViewers[] ELSE GrayViewers[];
grayLast ← NOT grayLast;
RETURN};
Check for change in gray in 8 bpp
(on = WindowManager.colorDisplayOn
AND Rope.Equal[monitorType, monitorTypeLast, FALSE]
AND Bpp[] # 8
AND gray # Gray[]
AND on) => {RETURN};
Check for just switching sides.
(on = WindowManager.colorDisplayOn
AND bpp = Bpp[]
AND bppB = BppB[]
AND Rope.Equal[monitorType, monitorTypeLast, FALSE]
AND gray=Gray[]
AND on) => {
IF Interminal.GetColorDisplaySide[] = left
THEN Interminal.SetColorDisplaySide[right]
ELSE Interminal.SetColorDisplaySide[left]};
Otherwise, we need to check the whole ball of wax
ENDCASE => TRUSTED {
colorViewerList, colorIconList: LIST OF ViewerClasses.Viewer ← NIL; --Really only viewers, tho
ListColorViewers: PROC ~ TRUSTED { -- Constructs a list of the color viewers
EnumColorViewers: ViewerOps.EnumProc ~ TRUSTED {
IF v.column=color THEN
IF v.iconic THEN colorIconList ← CONS[v,colorIconList] ELSE {
ViewerOps.CloseViewer[v, FALSE];
colorViewerList ← CONS[v, colorViewerList];
};
};
ViewerOps.EnumerateViewers[enum: EnumColorViewers];
ViewerOps.ComputeColumn[static];
};
ReopenColorViewers: PROC ~ TRUSTED { -- Reopen the listed color viewers
FOR each: LIST OF ViewerClasses.Viewer ← colorViewerList, each.rest UNTIL each=NIL DO
ViewerOps.ChangeColumn[each.first, color];
ViewerOps.OpenIcon[icon: each.first, paint: TRUE]; -- should be FALSE but call below to ComputeColumn doesn't repaint if no size change!
ENDLOOP;
ViewerOps.ComputeColumn[color];
Reset the icons that WOULD have been opened on the color display back there
FOR each: LIST OF ViewerClasses.Viewer ← colorIconList, each.rest UNTIL each=NIL DO
ViewerOps.ChangeColumn[each.first, color];
ENDLOOP;
};
side: WindowManager.ScreenPos ← IF onLeft THEN left ELSE right;
ok: BOOLFALSE;
onLeftLast ← onLeft;
bppLast ← bpp;
bppBLast ← bppB;
grayLast ← gray;
monitorTypeLast ← monitorType; --Back up the given parameters
ListColorViewers[]; -- Make a list of all the viewers on the color display (if any)
WindowManager.StopColorViewers[]; -- Turn off display
IF on THEN {
SELECT TRUE FROM
Rope.Equal[s1: monitorType, s2: "640x480", case: FALSE] => ok ← Start640Monitor[bitsPerPixel: bpp, bitsPerPixelB: bppB, pos: side];
Rope.Equal[s1: monitorType, s2: "1024x768", case: FALSE] => ok ← Start1024Monitor[bitsPerPixel: bpp, bitsPerPixelB: bppB, pos: side];
ENDCASE => MessageBlink["Invalid monitor type!!"];
IF NOT ok THEN
{MessageBlink["Can't turn on color!"];
RETURN};
IF bpp = 8 THEN
{IF grayLast THEN GrayViewers[] ELSE DefaultViewers[]};
ReopenColorViewers[];
};
};
};
StartMonitor: PROC [type: ColorDisplayDefs.ColorDisplayType, bitsPerPixel, bitsPerPixelB: CARDINAL,
pos: WindowManager.ScreenPos] ~ {
mode: ColorDisplayDefs.ColorMode ~ IF bitsPerPixel = 24 THEN ColorDisplayDefs.colorMode24 ELSE [FALSE, bitsPerPixel, bitsPerPixelB];
[]← ColorDisplayFace.SetDisplayType[type];
FOR try: CARDINAL IN [1..3] DO
[]← Terminal.SetColorMode[InterminalBackdoor.terminal, mode
! Terminal.CantDoIt => { --Try a bit of garbage collection
SELECT try FROM
1 => {
MessageWindow.Append["Couldn't allocate frame. Garbage collecting...", TRUE];
SafeStorage.ReclaimCollectibleObjects[];
LOOP;
};
2 => {
MessageWindow.Append[".....GARBAGE COLLECTING!!!"];
SafeStorage.ReclaimCollectibleObjects[traceAndSweep: TRUE];
LOOP;
};
3 => {
MessageWindow.Append["Couldn't do it. Sure you have a color display?", TRUE];
};
ENDCASE => ERROR;
};
];
ENDLOOP;
WindowManager.StartColorViewers[pos, bitsPerPixel];
};
Start640Monitor: PUBLIC PROCEDURE [bitsPerPixel: CARDINAL ← 8, bitsPerPixelB:CARDINAL ← 0, pos: WindowManager.ScreenPos ← left] RETURNS [ok: BOOLTRUE] = {
StartMonitor[standard, bitsPerPixel, bitsPerPixelB, pos];
};
Start1024Monitor: PUBLIC PROCEDURE [bitsPerPixel: CARDINAL ← 8, bitsPerPixelB:CARDINAL ← 0, pos: WindowManager.ScreenPos ← left] RETURNS [ok: BOOLTRUE] = {
IF bitsPerPixel = 24 THEN RETURN [FALSE];
StartMonitor[highResolution, bitsPerPixel, bitsPerPixelB, pos];
};
GetColorDisplayStatus: PUBLIC ENTRY PROC RETURNS [on, onLeft, gray: BOOLEAN, bpp, bppB: CARDINAL, monitorType: Rope.ROPE] ~ {
ENABLE UNWIND => NULL;
[on, onLeft, gray, bpp, bppB, monitorType] ← GetColorDisplayStatusInternal[];
};
GetCDState: INTERNAL PROC RETURNS [state: CDState] ~ INLINE {
[state.on, state.onLeft, state.gray, state.bpp, state.bppB, state.monitorType] ← GetColorDisplayStatusInternal[];
};
GetColorDisplayStatusInternal: INTERNAL PROC RETURNS [on, onLeft, gray: BOOLEAN, bpp, bppB: CARDINAL, monitorType: Rope.ROPE] ~ {
on ← WindowManager.colorDisplayOn;
onLeft ← OnLeft[];
bpp ← Bpp[];
bppB ← BppB[];
monitorType ← monitorTypeLast;
gray ← grayLast;
};
GetColorDisplayProfile: PUBLIC PROC RETURNS [on, onLeft, gray: BOOLEAN, bpp, bppB: CARDINAL, monitorType: Rope.ROPE] ~ {
RightOrLeft: PROC RETURNS[rl: Rope.ROPE] ~ INLINE {rl ← IF onLeftLast THEN "left" ELSE "right"};
tBpp, tBppB: INTEGER; --Temporary bits per pixel
on ← WindowManager.colorDisplayOn;
SELECT tBpp ← UserProfile.Number["ColorDisplay.BitsPerPoint", Bpp[]] FROM
1, 2, 4, 8, 24 => bpp ← tBpp;
ENDCASE => bpp ← Bpp[];
SELECT tBppB ← UserProfile.Number["ColorDisplay.BitsPerPointB", BppB[]] FROM
0, 1, 2 => bppB ← tBppB;
ENDCASE => bppB ← Bpp[];
onLeft ← Rope.Equal[UserProfile.Token["ColorDisplay.Side", RightOrLeft[]], "left", FALSE];
monitorType ← UserProfile.Token["ColorDisplay.Type", monitorTypeLast];
gray ← UserProfile.Boolean["ColorDisplay.Gray", grayLast];
};
procList: LIST OF REF NotifyRecord ← NIL; --Dummy
NotifyRecord: TYPE ~ RECORD [
proc: CDNotifyProc,
clientData: REF
];
RegisterCDNotifyProc: PUBLIC ENTRY PROC [proc: CDNotifyProc, clientData: REF] RETURNS [reg: CDRegistration] ~ {
ENABLE UNWIND => NULL;
state: CDState ~ GetCDState[];
ref: REF NotifyRecord ~ NEW[NotifyRecord ← [proc: proc, clientData: clientData]];
procList ← CONS[ref, procList];
TRUSTED {Process.Detach[FORK proc[state, state, clientData]]};
RETURN [ref]
};
UnregisterCDNotifyProc: PUBLIC ENTRY PROC [reg: CDRegistration] ~ {
ENABLE UNWIND => NULL;
ref: REF NotifyRecord ~ NARROW[reg];
WHILE procList # NIL AND procList.first = ref DO --Eliminate if at beginning
procList ← procList.rest;
ENDLOOP;
FOR p: LIST OF REF NotifyRecord ← procList, p.rest UNTIL p=NIL DO
WHILE p.rest # NIL AND p.rest.first = reg DO
p.rest ← p.rest.rest;
ENDLOOP;
ENDLOOP;
};
forCDChanges: CONDITION;
WatchForChanges: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
old, new: CDState ← GetCDState[];
DO
WHILE old = (new ← GetCDState[]) DO
WAIT forCDChanges;
ENDLOOP;
FOR each: LIST OF REF NotifyRecord ← procList, each.rest UNTIL each = NIL DO
TRUSTED {Process.Detach[FORK each.first.proc[old, new, each.first.clientData]];}
ENDLOOP;
old ← new;
ENDLOOP;
};
SleepColorDisplay: PUBLIC ENTRY UNSAFE PROC [ticks: Process.Ticks] ~ {
ENABLE UNWIND => NULL;
vt: Terminal.Virtual ← InterminalBackdoor.terminal;
state: Terminal.BitmapState ← Terminal.GetColorBitmapState[vt];
mode: Terminal.ColorMode ← Terminal.GetColorMode[vt];
visible: Terminal.ChannelsVisible ← Terminal.GetVisibility[vt];
IF state # displayed THEN RETURN;
[] ← Terminal.SetColorBitmapState[vt, allocated, mode, none];
Process.Pause[ticks];
[] ← Terminal.SetColorBitmapState[vt, state, mode, visible];
};
Context: TYPE ~ Imager.Context;
GrayCreateContext: PROC [screen: ViewerPrivate.Screen] RETURNS [context: Imager.Context] ~ {
terminal: Terminal.Virtual ~ InterminalBackdoor.terminal;
SELECT screen FROM
bw => context ← ImagerTerminal.BWContext[vt: terminal, pixelUnits: TRUE];
color => {
contextB, contextM: Imager.Context;
fb: Terminal.FrameBuffer ← Terminal.GetColorFrameBufferB[terminal];
context ← GrayContext[vt: terminal, pixelUnits: TRUE];
-- this should probably get its context from ImagerGray instead of
-- ImagerRaster.NewGrayDevice. However while it works don't fix it
-- Mik
IF fb#NIL AND ~Terminal.GetColorMode[terminal].full THEN {
frame: ImagerPixelMap.PixelMap ~ PixelMapFromFrameBuffer[fb];
contextB ← ImagerGray.Create[frame, $Intensity, ImagerGray.LikeScreen[frame.sSize], 1, NIL, NIL, TRUE];
contextM ← ImagerMaskContext.Create[contextB, ImagerColor.ColorFromGray[1]];
context ← ImagerForkContext.Create[context, contextM];
};
}
ENDCASE => ERROR;
};
DitherCreateContext: PROC [screen: ViewerPrivate.Screen] RETURNS [context: Imager.Context] ~ {
terminal: Terminal.Virtual ~ InterminalBackdoor.terminal;
SELECT screen FROM
bw => context ← ImagerTerminal.BWContext[vt: terminal, pixelUnits: TRUE];
color => {
contextB, contextM: Imager.Context;
fb: Terminal.FrameBuffer ← Terminal.GetColorFrameBufferB[terminal];
context ← ImagerTerminal.ColorContext[vt: terminal, pixelUnits: TRUE];
IF fb#NIL AND ~Terminal.GetColorMode[terminal].full THEN {
frame: ImagerPixelMap.PixelMap ~ PixelMapFromFrameBuffer[fb];
contextB ← ImagerGray.Create[frame, $Intensity, ImagerGray.LikeScreen[frame.sSize], 1, NIL, NIL, TRUE];
contextM ← ImagerMaskContext.Create[contextB, ImagerColor.ColorFromGray[1]];
context ← ImagerForkContext.Create[context, contextM];
};
};
ENDCASE => ERROR;
};
PixelMapFromFrameBuffer: PROC [frameBuffer: Terminal.FrameBuffer]
RETURNS
[ImagerPixelMap.PixelMap] ~ {
Lg: PROC [n: NAT] RETURNS [NAT] ~ {
RETURN[SELECT n FROM 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, ENDCASE => ERROR]
};
refRep: REF ImagerPixelMap.PixelMapRep ~ NEW[ImagerPixelMap.PixelMapRep ← [
ref: frameBuffer,
pointer: frameBuffer.base,
words: INT[frameBuffer.wordsPerLine]*INT[frameBuffer.height],
lgBitsPerPixel: Lg[frameBuffer.bitsPerPixel],
rast: frameBuffer.wordsPerLine,
lines: frameBuffer.height
]];
frame: ImagerPixelMap.PixelMap ~ [
sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0,
sSize: frameBuffer.height, fSize: frameBuffer.width, refRep: refRep
];
RETURN[frame];
};
gamma: REAL ← 2.2;
fontCacheID: ATOM ~ $ColorDisplay;
fontCacheSize: NAT ← 10000;
fontRastWeight: REAL ← 0.0;
GrayContext: PROC [vt: Terminal.Virtual, pixelUnits: BOOL] RETURNS [Context] ~ {
mode: Terminal.ColorMode ~ Terminal.GetColorMode[vt];
IF Terminal.GetColorBitmapState[vt]=none THEN RETURN[NIL]
ELSE {
frameBuffer: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferA[vt];
fontCache: ImagerCache.Ref ~ ImagerCache.GetNamedCache[
atom: fontCacheID, createSize: fontCacheSize];
device: ImagerDevice.Device ~ ImagerRaster.NewGrayDevice[vt];
[] ← Terminal.SetColorCursorPresentation[vt, onesAreBlack];
ImagerColorMap.SetStandardGrayMap[vt: vt, gamma: gamma];
RETURN[ImagerRaster.Create[device: device, pixelUnits: pixelUnits,
fontCache: fontCache, rastWeight: fontRastWeight]];
};
};
GrayViewers: PUBLIC PROC ~ {
[] ← ViewerPrivate.SetCreator[GrayCreateContext];
ViewerOps.PaintEverything[];
};
DefaultViewers: PUBLIC PROC ~ {
[] ← ViewerPrivate.SetCreator[DitherCreateContext];
ImagerColorMap.SetStandardColorMap[vt: InterminalBackdoor.terminal, gamma: gamma];
ViewerOps.PaintEverything[];
};
Init: PROC[] RETURNS[] ~ {
Read the user profile to establish the initial back settings...
-- DefaultViewers[];
[ , onLeftLast, grayLast, bppLast, bppBLast, monitorTypeLast] ← GetColorDisplayProfile[];
TRUSTED {
Process.SetTimeout[@forCDChanges, 300];
Process.Detach[FORK WatchForChanges[]];
};
Register the program with the commander and read user profile
Commander.Register[key:"ColorDisplay", proc: FiddleWithDisplay, doc: "Configure color monitor"];
Establish the 'color' button up at the top
[] ← Buttons.Create[
info: [name: "Color"],
proc: BugColor,
fork: FALSE
];
};
From ColorDisplayCommand
FiddleWithDisplay: Commander.CommandProc ~ {
MyLower: Rope.TranslatorType = BEGIN RETURN[Ascii.Lower[old]]; END;
myOn, myGray: BOOLEAN;
myBpp, myBppB: CARDINAL;
myOnLeft: BOOLEAN;
myMonType: Rope.ROPE;
noParams: BOOLEANTRUE;
s: IO.STREAMIO.RIS[Rope.Translate[base: cmd.commandLine, translator: MyLower]];
[myOn, myOnLeft, myGray, myBpp, myBppB, myMonType] ← GetColorDisplayStatus[];
DO
f: Rope.ROPEIO.GetTokenRope[s, IO.IDProc ! IO.EndOfStream => EXIT].token;
noParams ← FALSE;
SELECT Rope.Fetch[f, 0] FROM
'0 => myOn ← FALSE;
'1 =>
IF Rope.Equal[f, "1024x768"] THEN { myMonType ← "1024x768"; myOn ← TRUE }
ELSE IF Rope.Length[f]=1 THEN {myBpp ← 1; myOn ← TRUE; }
ELSE {
IO.PutF[cmd.err, "Option %g that begins with a 1 has to be 1024x768 or 1 exactly.\n", IO.rope[f]];
RETURN;
};
'2 =>
IF Rope.Equal[f, "24"] THEN { myOn ← TRUE; myBpp ← 24 }
ELSE IF Rope.Length[f]=1 THEN { myBpp ← 2; myOn ← TRUE }
ELSE {
IO.PutF[cmd.err, "Can't do %g bpp\n", IO.rope[f]];
RETURN;
};
'4 => { myBpp ← 4; myOn ← TRUE };
'6 => {
IF Rope.Equal[f, "640x480"] THEN { myMonType ← "640x480"; myOn ← TRUE }
ELSE {
IO.PutF[cmd.err, "%g is an invalid key\n", IO.rope[f]];
RETURN;
};
};
'8 => { myBpp ← 8; myOn ← TRUE };
'l => { myOnLeft ← TRUE; myOn ← TRUE };
'r => { myOnLeft ← FALSE; myOn ← TRUE };
'd => {
IF Rope.Equal[f, "default"]
THEN [myOn, myOnLeft, myGray, myBpp, myBppB, myMonType] ← GetColorDisplayProfile[]
ELSE {myGray ← FALSE; myOn ← TRUE };
};
'+ => {
SELECT TRUE FROM
Rope.Equal[f, "+2"] => { myBppB ← 2; myOn ← TRUE };
Rope.Equal[f, "+1"] => { myBppB ← 1; myOn ← TRUE };
Rope.Equal[f, "+0"] => { myBppB ← 0; myOn ← TRUE };
ENDCASE => {
IO.PutF[cmd.err, "valid B channel values are 0,1,2\n"];
RETURN;
};
};
'o =>
IF Rope.Equal[f, "on"] THEN myOn ← TRUE
ELSE IF Rope.Equal[f, "off"] THEN myOn ← FALSE
ELSE {
IO.PutF[cmd.err, "%g is an invalid key\n", IO.rope[f]];
RETURN;
};
'g => { myGray ← TRUE; myOn ← TRUE };
'? => IO.PutF[cmd.err, "%g, %g bpp, %g, %g, %g\n",
IO.rope[IF myOn THEN "on" ELSE "off"],
IO.card[myBpp],
IO.rope[IF myOnLeft THEN "left" ELSE "right"],
IO.rope[myMonType],
IO.rope[(IF myGray THEN "Gray" ELSE "Dither")]];
ENDCASE => {
IO.PutF[cmd.err, "%g is an invalid key\n", IO.rope[f]];
RETURN[];
};
ENDLOOP;
IF noParams THEN myOn ← ~myOn;
SetColorDisplayStatus[myOn, myOnLeft, myGray, myBpp, myBppB, myMonType];
};
ButtonSet: TYPE ~ RECORD [
on, off, left, right, lowres, highres, c1, c2, c4, c8, c24, gray, dither: Buttons.Button ← NIL,
reg: CDRegistration ← NIL,
cdt: Containers.Container ← NIL
];
CreateColorDisplayTool: PROC ~ {
bs: REF ButtonSet ~ NEW[ButtonSet];
prev: Buttons.Button;
hMargin: INT ~ -1;
hSeparator: INT ~ 10;
vMargin: INT ~ 5;
vHeight: INT ~ 10;
thisX, thisY: INT;
CreateCDTButton: PROC [name: Rope.ROPE, proc: Buttons.ButtonProc, extraOffset: INT ← 0] RETURNS [button: Buttons.Button] ~ {
button ← prev ← Buttons.Create[
info: [
name: name,
wx: thisX,
wy: thisY,
parent: bs.cdt,
border: TRUE
],
proc: proc
];
thisX ← thisX + prev.ww + hMargin + extraOffset;
};
bs.cdt ← Containers.Create[
info: [
name: "ColorDisplayTool",
column: right,
scrollable: FALSE
]
];
thisX ← hMargin+hSeparator; thisY ← vMargin;
The various buttons
bs.on ← CreateCDTButton["On", CDTOn];  --On Button
bs.off ← CreateCDTButton["Off", CDTOff, hSeparator]; --Off Button
bs.c1 ← CreateCDTButton["1 ", CDT1];   --1 Button
bs.c2 ← CreateCDTButton["2 ", CDT2];   --2 Button
bs.c4 ← CreateCDTButton["4 ", CDT4];   --4 Button
bs.c8 ← CreateCDTButton["8 ", CDT8];   --8 Button
bs.c24 ← CreateCDTButton["24 ", CDT24, hSeparator]; --24 Button
bs.left ← CreateCDTButton["Left", CDTLeft];  --Left Button
bs.right ← CreateCDTButton["Right", CDTRight, hSeparator]; --Right Button
bs.lowres ← CreateCDTButton["640x480", CDTLowRes]; --640x480 Button
bs.highres ← CreateCDTButton["1024x768", CDTHighRes, hSeparator]; --1024x768 Button
bs.gray ← CreateCDTButton["Gray", CDTGray];
bs.dither ← CreateCDTButton["Dither", CDTDither, hSeparator];
bs.reg ← RegisterCDNotifyProc[MonitorButtons, bs];
Set the height of the viewer as a whole
ViewerOps.SetOpenHeight[bs.cdt, thisY + vHeight + 2*vMargin];
ViewerOps.OpenIcon[icon: bs.cdt, bottom: FALSE];
};
shouldBeLit: ARRAY BOOLEAN OF ATOM ~ [$BlackOnWhite, $WhiteOnBlack];
MonitorButtons: CDNotifyProc ~ {
Repaint: PROC [button: Buttons.Button, condition: BOOLEAN] ~ INLINE {
OPEN Buttons;
Buttons.SetDisplayStyle[button, shouldBeLit[condition]];
};
This proc toggles the color of the buttons to show currect state of display
bs: REF ButtonSet ~ NARROW[clientData];
IF bs.cdt=NIL OR bs.cdt.destroyed THEN { --No point blowing ourselves to smithereens.
UnregisterCDNotifyProc[bs.reg];
RETURN;
};
Repaint[bs.on, new.on];
Repaint[bs.off, ~ new.on];
Repaint[bs.c1, new.bpp = 1];
Repaint[bs.c2, new.bpp = 2];
Repaint[bs.c4, new.bpp = 4];
Repaint[bs.c8, new.bpp = 8];
Repaint[bs.c24, new.bpp = 24];
Repaint[bs.left, new.onLeft];
Repaint[bs.right, ~ new.onLeft];
Repaint[bs.lowres, new.monitorType.Equal["640x480"]];
Repaint[bs.highres, ~ new.monitorType.Equal["640x480"]];
Repaint[bs.gray, new.gray];
Repaint[bs.dither, ~ new.gray];
};
CDTOn: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: TRUE]};
CDTOff: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: FALSE]};
CDTLeft: Buttons.ButtonProc ~ {SetColorDisplayStatus[onLeft: TRUE]};
CDTRight: Buttons.ButtonProc ~ {SetColorDisplayStatus[onLeft: FALSE]};
CDTLowRes: Buttons.ButtonProc ~ {SetColorDisplayStatus[monitorType: "640x480"]};
CDTHighRes: Buttons.ButtonProc ~ {SetColorDisplayStatus[monitorType: "1024x768"]};
CDT1: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: FALSE, bpp: 1]};
CDT2: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: FALSE, bpp: 2]};
CDT4: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: FALSE, bpp: 4]};
CDT8: Buttons.ButtonProc ~ {SetColorDisplayStatus[on: FALSE, bpp: 8]};
CDT24: Buttons.ButtonProc ~ {
IF grayLast
THEN MessageBlink["Can't be gray and 24bpp."]
ELSE SetColorDisplayStatus[on: FALSE, bpp: 24, gray: FALSE, monitorType: "640x480"];
};
CDTGray: Buttons.ButtonProc ~ {
IF bppLast = 24
THEN MessageBlink["Can't be gray and 24bpp."]
ELSE SetColorDisplayStatus[gray: TRUE];
};
CDTDither: Buttons.ButtonProc ~ {SetColorDisplayStatus[gray: FALSE]};
BugColor: Buttons.ButtonProc ~ {
SELECT mouseButton FROM
red => SetColorDisplayStatus[on: ~GetColorDisplayStatus[].on];
yellow => TRUSTED {SleepColorDisplay[300]};
blue => CreateColorDisplayTool[];
ENDCASE;
};
Init[];
END.