-- ColorDisplayImpl.mesa
-- Last edited by Stone on June 9, 1982 4:02 pm 

DIRECTORY
  ColorDisplay USING [disconnected, Mode, NotifyCursor],
  ColorDisplayFace USING [baseA, baseB, baseC, bplA, bplB, bplC, Connect, Disconnect,
    displayType, GetBlueMap, GetColor, GetGreenMap, GetRedMap, globalStateSize, HasMode,
    height, Initialize, InitializeCleanup, mixedRG, Mode, PagesForMode, pixelsPerInch,
    SetBlueMap, SetColor, SetGreenMap, SetRedMap, Show, TurnOff, TurnOn, width],
  DriverStartChain USING [Start],
  Environment USING [Base, bitsPerWord, PageCount, PageNumber, PageOffset],
  ResidentHeap USING [MakeNode],
  Runtime USING [CallDebugger],
  Space USING [Create, defaultBase, defaultWindow, Delete, Handle, Map,
    nullHandle, PageCount, PageNumber, virtualMemory, VMPageNumber],
  SpecialSpace USING [MakeResident, MakeSwappable, realMemorySize],
  Transaction USING [Handle, nullHandle],
  Zone USING [Base, Status];

ColorDisplayImpl: MONITOR
  IMPORTS
    ColorDisplayFace, OtherDrivers: DriverStartChain, ResidentHeap, Runtime,
    Space, SpecialSpace, Transaction, ColorDisplay
  EXPORTS DriverStartChain, ColorDisplay = {

  Mode: TYPE = ColorDisplay.Mode;
  disconnected: Mode = ColorDisplay.disconnected;

  -- Interface variables

  pixelsPerInch: PUBLIC CARDINAL ← 0;
  displayType: PUBLIC CARDINAL ← 0;
  mixedRG: PUBLIC BOOLEAN ← FALSE;

  curmode: PUBLIC Mode ← disconnected;
  width,height: PUBLIC CARDINAL ← 0;
  baseA,baseB,baseC: PUBLIC LONG POINTER ← NIL;
  wplA,wplB,wplC: PUBLIC CARDINAL ← 0;

  ValidMode: PROC[m: Mode] RETURNS[BOOLEAN] = {
    Ok: PROC[b: [0..8]] RETURNS[BOOLEAN] = INLINE {
      RETURN[SELECT b FROM 0,1,2,4,8 => TRUE, ENDCASE => FALSE] };
    RETURN[m.full OR (Ok[m.bitsPerPixelA] AND Ok[m.bitsPerPixelB])] };

  FMode: PROC[m: Mode] RETURNS[ColorDisplayFace.Mode] = {
    Log: PROC[b: [0..8]] RETURNS[[0..4)] = INLINE {
      RETURN[SELECT b FROM 1=>0, 2=>1, 4=>2, 8=>3, ENDCASE => 0] };
    fm: ColorDisplayFace.Mode ← [full: FALSE,
      useA: FALSE, useB: FALSE, lgBitsPerPixelA: 0, lgBitsPerPixelB: 0];
    IF m.full THEN fm.full ← TRUE
    ELSE {
      IF m.bitsPerPixelA>0 THEN { fm.useA ← TRUE; fm.lgBitsPerPixelA ← Log[m.bitsPerPixelA] };
      IF m.bitsPerPixelB>0 THEN { fm.useB ← TRUE; fm.lgBitsPerPixelB ← Log[m.bitsPerPixelB] };
      };
    RETURN[fm];
    };

  HasMode: PUBLIC ENTRY PROC[mode: Mode] RETURNS [BOOLEAN] = {
    RETURN[SELECT TRUE FROM
      (mode=disconnected) => TRUE,
      (displayType=0) => FALSE,
      ValidMode[mode] => ColorDisplayFace.HasMode[FMode[mode]],
      ENDCASE => FALSE] };

  space: Space.Handle ← Space.nullHandle;
  workingSet: Space.PageCount = 750; -- a guess

  SetMode: PUBLIC ENTRY PROC [mode: Mode] RETURNS [BOOLEAN] = {
    IF mode=curmode THEN RETURN[TRUE];
    IF displayType=0 THEN RETURN[FALSE];
    IF curmode#disconnected THEN { -- disconnect
      IF state=on THEN InternalTurnOff[];
      curmode ← disconnected;
      width ← height ← 0;
      baseA ← baseB ← baseC ← NIL;
      wplA ← wplB ← wplC ← 0;
      ColorDisplayFace.Disconnect[];
      Space.Delete[space];
      space ← Space.nullHandle;
      };
    IF NOT ValidMode[mode] THEN RETURN[FALSE];
    IF mode#disconnected THEN { -- connect
      fmode: ColorDisplayFace.Mode ← FMode[mode];
      pages: Environment.PageCount;
      swapUnitSize: CARDINAL = 50;
      IF NOT ColorDisplayFace.HasMode[fmode] THEN RETURN[FALSE];
      pages ← ColorDisplayFace.PagesForMode[fmode];
      IF mode.full THEN pages ← MIN[pages,SpecialSpace.realMemorySize-workingSet];
      space ← Space.Create[size: pages,
        parent: Space.virtualMemory, base: Space.defaultBase];
      FOR offset: CARDINAL ← 0, offset + swapUnitSize
      WHILE offset + swapUnitSize <= pages DO
        [] ← Space.Create[size: swapUnitSize, parent: space, base: offset]
        ENDLOOP;
      Space.Map[space: space, window: Space.defaultWindow];
      ColorDisplayFace.Connect[fmode,Space.VMPageNumber[space],pages];
      baseA ← ColorDisplayFace.baseA;
      baseB ← ColorDisplayFace.baseB;
      baseC ← ColorDisplayFace.baseC;
      IF ColorDisplayFace.bplA MOD Environment.bitsPerWord # 0 THEN ERROR;
      IF ColorDisplayFace.bplB MOD Environment.bitsPerWord # 0 THEN ERROR;
      IF ColorDisplayFace.bplC MOD Environment.bitsPerWord # 0 THEN ERROR;
      wplA ← ColorDisplayFace.bplA/Environment.bitsPerWord;
      wplB ← ColorDisplayFace.bplB/Environment.bitsPerWord;
      wplC ← ColorDisplayFace.bplC/Environment.bitsPerWord;
      width ← ColorDisplayFace.width;
      height ← ColorDisplayFace.height;
      };
    IF mode.full THEN FOR i: [0..256) IN [0..256) DO
      ColorDisplayFace.SetRedMap[i,i];
      ColorDisplayFace.SetGreenMap[i,i];
      ColorDisplayFace.SetBlueMap[i,i];
      ENDLOOP;
    curmode ← mode; ColorDisplay.NotifyCursor[]; RETURN[TRUE];
    };

  state: {off, on} ← off;

  TurnOn: PUBLIC ENTRY PROC = {
    IF curmode=disconnected OR state=on THEN RETURN;
    SpecialSpace.MakeResident[space];
    ColorDisplayFace.TurnOn[];
    state ← on;
    };

  TurnOff: PUBLIC ENTRY PROC = {
    IF curmode=disconnected OR state=off THEN RETURN;
    InternalTurnOff[];
    };

  InternalTurnOff: INTERNAL PROC = INLINE {
    ColorDisplayFace.TurnOff[];
    SpecialSpace.MakeSwappable[space];
    state ← off;
    };

  Show: PUBLIC ENTRY PROC[a,b,c: BOOLEAN] = {
    IF curmode=disconnected THEN RETURN;
    ColorDisplayFace.Show[a,b,c];
    };

  GetColor: PUBLIC ENTRY PROC [pixelA,pixelB: CARDINAL] RETURNS[r,g,b: [0..256)] = {
    IF curmode=disconnected OR curmode.full THEN RETURN[0,0,0];
    [r: r, g: g, b: b] ← ColorDisplayFace.GetColor[pixelA,pixelB];
    };

  SetColor: PUBLIC ENTRY PROC [pixelA,pixelB: CARDINAL, r,g,b: [0..256)] = {
    IF curmode=disconnected OR curmode.full THEN RETURN;
    ColorDisplayFace.SetColor[pixelA: pixelA, pixelB: pixelB, r: r, g: g, b: b];
    };

-- Procedures for 24 bit per pixel mode

  GetRedMap: PUBLIC ENTRY PROC[in: [0..256)] RETURNS[out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN[0];
    RETURN[ColorDisplayFace.GetRedMap[in]];
    };
  GetGreenMap: PUBLIC ENTRY PROC[in: [0..256)] RETURNS[out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN[0];
    RETURN[ColorDisplayFace.GetGreenMap[in]];
    };
  GetBlueMap: PUBLIC ENTRY PROC[in: [0..256)] RETURNS[out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN[0];
    RETURN[ColorDisplayFace.GetBlueMap[in]];
    };

  SetRedMap: PUBLIC ENTRY PROC[in,out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN;
    ColorDisplayFace.SetRedMap[in: in, out: out];
    };
  SetGreenMap: PUBLIC ENTRY PROC[in,out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN;
    ColorDisplayFace.SetGreenMap[in: in, out: out];
    };
  SetBlueMap: PUBLIC ENTRY PROC[in,out: [0..256)] = {
    IF curmode=disconnected OR NOT curmode.full THEN RETURN;
    ColorDisplayFace.SetBlueMap[in: in, out: out];
    };

  -- Initialization

  Start: PUBLIC PROCEDURE = {OtherDrivers.Start[]};

  StartHead: PROCEDURE = {
    headGlobalP: Zone.Base RELATIVE POINTER;
    s: Zone.Status;
    [headGlobalP, s] ← ResidentHeap.MakeNode[ColorDisplayFace.globalStateSize];
    IF s # okay THEN Runtime.CallDebugger["Zone error in ColorDisplayImpl"L];
    ColorDisplayFace.Initialize[headGlobalP];
    ColorDisplayFace.InitializeCleanup[]};
 
   displayType ← ColorDisplayFace.displayType;
  -- dont't initialize the head if there's no color display!
  IF displayType#0 THEN {
    StartHead[];
    pixelsPerInch ← ColorDisplayFace.pixelsPerInch;
    mixedRG ← ColorDisplayFace.mixedRG;
    };

  }.

Wyatt  25-Aug-81 17:39:01
  increase workingSet from 512 to 750

Wyatt   4-Mar-82 14:55:41
  prevent disaster when color display was absent (blush!)

Levin  22-Mar-82 12:40:43
  change start logic to conform to normal driver conventions
  
Stone June 9, 1982 4:03 pm
  change SetMode to notify the color cursor implimentation