-- DiagnosticsImplB.mesa  -  edited by:
-- Poskanzer		17-Mar-83 20:07:15

DIRECTORY
  BitBlt USING [
    AlignedBBTable, BBptr, BBTable, BBTableSpace, BitAddress, BITBLT, DstFunc,
    GrayParm],
  Cursor USING [Set],
  DiagnosticsOps USING [calledByBye],
  Environment USING [bitsPerWord, Long],
  Inline USING [LongMult],
  OnlineDiagnostics USING [
    Background, Coordinate, CursorArray, KeyboardAndMouseTest, KeyboardType,
    LFDisplayTest, NextAction],
  RecOps USING [RecList, Convert, Free],
  TIP USING [FlushUserInput, globalTable, NewManager, NotifyProc],
  UserTerminal USING [
    Background, Beep, CursorArray, Coordinate, GetBackground, GetBitBltTable,
    hasBorder, keyboard, mouse, screenHeight, screenWidth, SetBackground,
    SetBorder, SetCursorPattern, SetCursorPosition, SetMousePosition],
  Window USING [rootWindow, ValidateTree],
  WindowOps USING [InvalidateTree, rootWindow];

DiagnosticsImplB: PROGRAM
  IMPORTS
    BitBlt, Cursor, DiagnosticsOps, Inline, OnlineDiagnostics, RecOps, TIP,
    UserTerminal, Window, WindowOps
  EXPORTS DiagnosticsOps =
  BEGIN

  oldBackground: UserTerminal.Background;

  Bump: PROCEDURE [address: BitBlt.BitAddress, offset: LONG CARDINAL]
    RETURNS [BitBlt.BitAddress] =
    -- Alters a BitAddress by an offset
    BEGIN
    LowHalf: PROCEDURE [u: LONG UNSPECIFIED] RETURNS [UNSPECIFIED] =
      BEGIN l: any Environment.Long = LOOPHOLE[u]; RETURN[l.low]; END;
    offset ← offset + LONG[address.bit];
    RETURN[
      [
        word: address.word + (offset/Environment.bitsPerWord), reserved: 0,
        bit: LowHalf[offset] MOD Environment.bitsPerWord]];
    END;

  SetBackground: PROCEDURE [background: OnlineDiagnostics.Background] =
    BEGIN
    [] ← UserTerminal.SetBackground[
      IF background = black THEN black ELSE white];
    END;

  FixDisplay: PROCEDURE =
    BEGIN
    recList: RecOps.RecList = RecOps.Convert[Window.rootWindow];
    -- Reset the cursor to normal.
    Cursor.Set[textPointer];
    -- Fix up the border pattern and background
    SetBackground[white];
    IF UserTerminal.hasBorder THEN
      IF DiagnosticsOps.calledByBye THEN
        UserTerminal.SetBorder[evenPairs: 377B, oddPairs: 377B]
      ELSE
        UserTerminal.SetBorder[evenPairs: 42B, oddPairs: 210B];
    -- Tell them all to repaint themselves
    WindowOps.InvalidateTree[WindowOps.rootWindow, recList, FALSE];
    RecOps.Free[recList];
    Window.ValidateTree[];
    RestoreBackground[];  -- to state of desktop before test
    TIP.FlushUserInput[];
    TIP.NewManager[Window.rootWindow, NIL, NIL];
    END;

  SaveBackground: PROCEDURE =
    BEGIN oldBackground ← UserTerminal.GetBackground[]; END;
  
  RestoreBackground: PROCEDURE =
    BEGIN [] ← UserTerminal.SetBackground[oldBackground]; END;

  TipNop: TIP.NotifyProc = BEGIN END;


  KeyboardAndMouseTest: PUBLIC PROCEDURE =
    BEGIN
    bBTableSpace: BitBlt.BBTableSpace;
    bBptr: BitBlt.BBptr ← BitBlt.AlignedBBTable[@bBTableSpace];
    bitAddress: BitBlt.BitAddress;
    paintCan: LONG CARDINAL;

    ClearDisplay: PROCEDURE =
      BEGIN
      bBptr.dst ← bitAddress;
      bBptr.flags.dstFunc ← BitBlt.DstFunc[null];
      bBptr.width ← UserTerminal.screenWidth;
      bBptr.height ← UserTerminal.screenHeight;
      paintCan ← 0B;
      BitBlt.BITBLT[bBptr];
      END;

    BlackenScreen: PROCEDURE [x, y, width, height: CARDINAL] =
      BEGIN
      bBptr.flags.dstFunc ← BitBlt.DstFunc[null];
      bBptr.dst ← Bump[bitAddress, Inline.LongMult[bBptr.dstBpl, y]];
      bBptr.dst ← Bump[bBptr.dst, x];
      bBptr.width ← width;
      bBptr.height ← height;
      paintCan ← 37777777777B;
      BitBlt.BITBLT[bBptr];
      END;

    InvertScreen: PROCEDURE [x, y, width, height: CARDINAL] =
      BEGIN
      bBptr.flags.dstFunc ← BitBlt.DstFunc[xor];
      bBptr.dst ← Bump[bitAddress, Inline.LongMult[bBptr.dstBpl, y]];
      bBptr.dst ← Bump[bBptr.dst, x];
      bBptr.width ← width;
      bBptr.height ← height;
      paintCan ← 37777777777B;
      BitBlt.BITBLT[bBptr];
      END;

    Beep: PROCEDURE [duration: CARDINAL] =
      BEGIN UserTerminal.Beep[duration: duration]; END;

    GetMousePosition: PROCEDURE RETURNS [OnlineDiagnostics.Coordinate] =
      BEGIN RETURN[LOOPHOLE[UserTerminal.mouse↑]]; END;

    WaitForKeyTransition: PROCEDURE = BEGIN END;

    -- Turn the user input handler off
    TIP.NewManager[Window.rootWindow, TIP.globalTable[root], TipNop];

    -- Initialize Keyboard Test
    SaveBackground[];  -- remember if desktop screen was inverted
    bBptr↑ ← UserTerminal.GetBitBltTable[];
    bBptr.src.word ← LONG[@paintCan];
    bBptr.src.bit ← 0;
    bBptr.srcDesc ← [gray[BitBlt.GrayParm[0, 0, 0, 1]]];
    bBptr.flags.gray ← bBptr.flags.disjoint ← TRUE;
    bitAddress ← bBptr.dst;

    OnlineDiagnostics.KeyboardAndMouseTest[
      american, UserTerminal.screenHeight, UserTerminal.screenWidth,
      SetBackground, UserTerminal.SetBorder, GetMousePosition,
      LOOPHOLE[UserTerminal.SetMousePosition],
      LOOPHOLE[UserTerminal.SetCursorPattern],
      LOOPHOLE[UserTerminal.SetCursorPosition], LOOPHOLE[UserTerminal.keyboard],
      Beep, ClearDisplay, BlackenScreen, InvertScreen, WaitForKeyTransition];

    -- Fix up the display
    ClearDisplay[];
    FixDisplay[];
    END;


  LFDisplayTest: PUBLIC PROCEDURE =
    BEGIN
    bBTableSpace: BitBlt.BBTableSpace;
    bBptr: BitBlt.BBptr = BitBlt.AlignedBBTable[@bBTableSpace];
    bitAddress: BitBlt.BitAddress;
    paintCan: LONG CARDINAL;
    bitsIn24Lines: CARDINAL;

    ClearDisplay: PROCEDURE =
      BEGIN
      bBptr.dst ← bitAddress;
      bBptr.width ← UserTerminal.screenWidth;
      bBptr.height ← UserTerminal.screenHeight;
      bBptr.src.word ← @paintCan;
      paintCan ← 0B;
      bBptr.srcDesc ← [gray[BitBlt.GrayParm[0, 0, 0, 1]]];
      BitBlt.BITBLT[bBptr];
      END;

    BlackenScreen: PROCEDURE [x, y, width, height: CARDINAL] =
      BEGIN
      bBptr.dst ← Bump[bitAddress, Inline.LongMult[bBptr.dstBpl, y]];
      bBptr.dst ← Bump[bBptr.dst, x];
      bBptr.width ← width;
      bBptr.height ← height;
      bBptr.src.word ← @paintCan;
      paintCan ← 37777777777B;
      bBptr.srcDesc ← [gray[BitBlt.GrayParm[0, 0, 0, 1]]];
      BitBlt.BITBLT[bBptr];
      END;

    FillScreenWithObject: PROCEDURE [p: LONG POINTER TO ARRAY [0..16) OF WORD] =
      BEGIN
      bBptr.dst ← bitAddress;
      bBptr.width ← UserTerminal.screenWidth;
      bBptr.height ← UserTerminal.screenHeight;
      bBptr.src.word ← p;
      bBptr.srcDesc ← [gray[BitBlt.GrayParm[0, 0, 0, 15]]];
      BitBlt.BITBLT[bBptr];
      END;

    GetNextAction: PROCEDURE
      RETURNS [nextAction: OnlineDiagnostics.NextAction] =
      BEGIN
      -- Watch the keyboard until a key is typed (down)
      KeyName: TYPE = MACHINE DEPENDENT{
        (0), (16), (32), I(39), (48), Delete(62), (64), Space(73), Stop(77),
        (79)};

      SetOfKeys: TYPE = PACKED ARRAY KeyName OF MACHINE DEPENDENT{
        down(0), up(1)};
      Keys: LONG POINTER TO SetOfKeys = LOOPHOLE[UserTerminal.keyboard];

      WHILE Keys[I] = down OR Keys[Delete] = down OR Keys[Space] = down
        OR Keys[Stop] = down DO ENDLOOP;
      DO
        IF Keys[I] = down THEN RETURN[invertPattern];
        IF Keys[Delete] = down THEN RETURN[quit];
        IF Keys[Stop] = down THEN RETURN[quit];
        IF Keys[Space] = down THEN RETURN[nextPattern];
        ENDLOOP;
      END;

    -- Turn the user input handler off
    TIP.NewManager[Window.rootWindow, TIP.globalTable[root], TipNop];

    -- Initialize LF Display Test
    SaveBackground[];  -- remember if desktop screen was inverted
    bBptr↑ ← UserTerminal.GetBitBltTable[];
    bBptr.src.word ← LONG[@paintCan];
    bBptr.src.bit ← 0;
    bBptr.flags.gray ← bBptr.flags.disjoint ← TRUE;
    bBptr.flags.dstFunc ← BitBlt.DstFunc[null];
    bitAddress ← bBptr.dst;
    bitsIn24Lines ← 24*bBptr.dstBpl;

    UserTerminal.SetCursorPattern[ALL[0]];
    OnlineDiagnostics.LFDisplayTest[
      UserTerminal.screenHeight, UserTerminal.screenWidth, SetBackground,
      UserTerminal.SetBorder, GetNextAction, ClearDisplay, BlackenScreen,
      FillScreenWithObject];

    -- Fix up the display
    ClearDisplay[];
    FixDisplay[];
    END;

  END.