-- Copyright (C) 1981, 1982, 1984  by Xerox Corporation. All rights reserved. 
-- GateDMT.mesa, HGM,  1-Dec-84 18:51:34
-- From DMT.mesa of  7-Aug-81 17:33:38, updated to DMT of 24-Nov-82  8:20:42
-- Updated to DMT of 26-May-83 10:51:55

DIRECTORY
  Display USING [Black, Block, MeasureBlock, replaceFlags, Text, White],
  Environment USING [Block],
  Exec USING [AddCommand, ExecProc],
  Inline USING [LowHalf],
  MouseFace USING [Point, position, SetPosition],
  Process USING [
    Abort, Detach, EnableAborts, priorityNormal, SecondsToTicks, SetPriority, Pause],
  String USING [AppendChar],
  System USING [GetClockPulses, GreenwichMeanTime],
  Time USING [Current, Unpack, Unpacked],
  ToolFont USING [StringWidth],
  ToolWindow USING [
    Activate, AdjustProcType, Create, CreateSubwindow, Deactivate,
    DisplayProcType, Show, TransitionProcType],
  UserInput USING [
    AttentionProcType, ClearInputFocusOnMatch, SetAttention, SetInputFocus],
  UserTerminal USING [
    Background, hasBorder, screenHeight, screenWidth, SetBackground, SetBorder],
  Window USING [
    Box, Dims, GetParent, Handle, SetDisplayProc, Slide, ValidateTree],
  WindowFont USING [defaultFont, FontHeight, Handle];


GateDMT: MONITOR
  IMPORTS
    Display, Exec, Inline, MouseFace, Process, String, System, Time,
    ToolFont, ToolWindow, UserInput, UserTerminal, Window, WindowFont =
  BEGIN

  seed: CARDINAL;

  Random: PROCEDURE [low, high: CARDINAL ← 0] RETURNS [val: CARDINAL] =
    BEGIN
    seed ← seed + Inline.LowHalf[System.GetClockPulses[]];
    RETURN[IF high = 0 THEN seed ELSE ((seed MOD (high-low+1)) + low)];
    END;

  margin: CARDINAL = 4 + 4 + 4;
  separation: CARDINAL = 2;

  toolWindow, subWindow: Window.Handle ← NIL;
  swBox: Window.Box;

  running: BOOLEAN ← FALSE;

  wait: CONDITION ← [timeout: Process.SecondsToTicks[5]];
  bouncer: PROCESS;

  Run: ENTRY PROCEDURE =
    BEGIN
    ENABLE UNWIND => NULL;
    oldBackground: UserTerminal.Background ← UserTerminal.SetBackground[white];
    IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[377B, 377B];
    DO
      ENABLE ABORTED => EXIT;
      WAIT wait;
      PaintTime[Time.Current[], FALSE];
      IF Random[high: 2] # 0 THEN LOOP;
      Window.Slide[
        subWindow,
        swBox.place ← [
	  x: Random[high: UserTerminal.screenWidth-swBox.dims.w],
          y: Random[high: UserTerminal.screenHeight-swBox.dims.h]]];
      [] ← Window.SetDisplayProc[subWindow, InternalDisplay];
      Window.ValidateTree[];
      [] ← Window.SetDisplayProc[subWindow, EntryDisplay];
      ENDLOOP;
    running ← FALSE;
    [] ← UserTerminal.SetBackground[oldBackground];
    IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[210B, 42B];
    END;

  EntryDisplay: ENTRY ToolWindow.DisplayProcType = {
    ENABLE UNWIND => NULL; PaintTime[Time.Current[], TRUE]};

  InternalDisplay: INTERNAL ToolWindow.DisplayProcType = {
    PaintTime[Time.Current[], TRUE]};

  -- Time Painting

  displayed: RECORD [seconds: [0..60), weekday: [0..7)];

  PaintTime: INTERNAL PROCEDURE [time: System.GreenwichMeanTime, all: BOOLEAN] =
    BEGIN OPEN ToolFont;
    font: WindowFont.Handle ← WindowFont.defaultFont;
    timeWidth: CARDINAL;
    unp: Time.Unpacked ← Time.Unpack[time];
    s: STRING ← [8];
    AppendDec2: PROCEDURE [n: CARDINAL] =
      BEGIN
      String.AppendChar[s, '0 + n/10];
      String.AppendChar[s, '0 + n MOD 10];
      END;
    AppendDec2[unp.hour];
    String.AppendChar[s, ':];
    AppendDec2[unp.minute];
    String.AppendChar[s, ':];
    AppendDec2[unp.second];
    timeWidth ← StringWidth[s, font];
    IF all OR displayed.weekday # unp.weekday THEN
      BEGIN
      weekdays: STRING = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"L;
      offsets: ARRAY [0..7] OF CARDINAL = [0, 6, 13, 22, 30, 36, 44, 50];
      day: CARDINAL = unp.weekday;
      one: CARDINAL ← margin/3;
      two: CARDINAL = 2*one;
      dayBlock: Environment.Block = [
	LOOPHOLE[LONG[@weekdays.text]],
	offsets[day], offsets[day+1]];
      dayWidth: CARDINAL = Display.MeasureBlock[
        window: subWindow, block: dayBlock, place: [0,0]].newPlace.x;
      Display.White[subWindow, [[0, 0], swBox.dims]];
      Display.Black[
        subWindow, [[one, one], [swBox.dims.w - 2*one, swBox.dims.h - 2*one]]];
      Display.White[
        subWindow, [[two, two], [swBox.dims.w - 2*two, swBox.dims.h - 2*two]]];
      [] ← Display.Block[
        window: subWindow,
	block: dayBlock,
	place: [x: (swBox.dims.w-dayWidth)/2, y: margin],
	flags: Display.replaceFlags];
      END;
    [] ← Display.Text[
      window: subWindow,
      string: s,
      place: [
        x: (swBox.dims.w - timeWidth)/2,
        y: WindowFont.FontHeight[font] + margin + separation], font: font,
      flags: Display.replaceFlags];
    displayed ← [unp.second, unp.weekday];
    RETURN
    END;

  AdjustProc: ENTRY ToolWindow.AdjustProcType = {};

  AttentionProc: ENTRY UserInput.AttentionProcType = {
    Process.Detach[FORK StopRunning[toolWindow]]};

  StopRunning: PROCEDURE [w: Window.Handle] = {
    Process.SetPriority[Process.priorityNormal];
    [] ← ToolWindow.Deactivate[w]};

  StartRunning: ENTRY PROC [window: Window.Handle] = {
    IF running THEN RETURN;
    IF subWindow = NIL THEN subWindow ← ToolWindow.CreateSubwindow[
      parent: window, display: EntryDisplay, box: swBox];
    UserInput.SetInputFocus[subWindow, NIL, FALSE];
    UserInput.SetAttention[subWindow.GetParent[], AttentionProc];
    UserInput.SetAttention[subWindow, AttentionProc];
    bouncer ← FORK Run;
    running ← TRUE};

  TransitionProc: ToolWindow.TransitionProcType = {
    ENABLE UNWIND => NULL;
    SELECT new FROM
      inactive, tiny => {
        IF old = active THEN {
          UserInput.ClearInputFocusOnMatch[subWindow];
	  Process.Abort[bouncer];
	  JOIN bouncer};
	IF new = inactive THEN subWindow ← NIL};
      active => IF old # active THEN StartRunning[window];
      ENDCASE};
  

  DMTCommand: Exec.ExecProc = {ToolWindow.Activate[toolWindow]};

  Init: PROCEDURE =
    BEGIN OPEN ToolFont;
    swBox.dims.w ← StringWidth["Wednesday"L, WindowFont.defaultFont] + 2*margin;
    swBox.dims.h ← 2*WindowFont.FontHeight[WindowFont.defaultFont] + 2*margin + 2;
    swBox.place ← [0,0];
    toolWindow ← ToolWindow.Create[
      name: "GateDMT"L, adjust: AdjustProc, transition: TransitionProc,
      box: [place: [0,0], dims: [w: UserTerminal.screenWidth, h: UserTerminal.screenHeight]],
      initialState: active, named: FALSE];
    TransitionProc[window: toolWindow, old: inactive, new: active];
    ToolWindow.Show[toolWindow];
    Exec.AddCommand["DMT.~"L, DMTCommand];
    Process.EnableAborts[@wait];
    END;

  KillCopyright: PROCEDURE =
    BEGIN
    initialPosition: MouseFace.Point ← MouseFace.position↑;
    Process.Pause[Process.SecondsToTicks[10*60]];
    IF initialPosition # MouseFace.position↑ THEN RETURN;
    FOR i: CARDINAL IN [100..500) DO
      MouseFace.SetPosition[[i, i]];
      Process.Pause[1];
      ENDLOOP;
    END;

  Init[];
  Process.Detach[FORK KillCopyright[]];

  END...