~
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 BOOLEAN ← TRUE;
grayLast: PUBLIC BOOLEAN ← FALSE;
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: BOOL ← FALSE;
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:
BOOL ←
TRUE] = {
StartMonitor[standard, bitsPerPixel, bitsPerPixelB, pos];
};
Start1024Monitor:
PUBLIC
PROCEDURE [bitsPerPixel:
CARDINAL ← 8, bitsPerPixelB:
CARDINAL ← 0, pos: WindowManager.ScreenPos ← left]
RETURNS [ok:
BOOL ←
TRUE] = {
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];
};
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
];
};