-- ByeImplA.mesa  -  edited by:
-- Bruce 	 	1-Jun-83 12:04:23
-- Poskanzer		26-Apr-83 10:56:42
-- DonWinter 		22-Aug-83 17:22:09
-- JFung.pasa	        23-Jan-84 14:54:37       

DIRECTORY
     ByeOps,
     ComSoftOps USING [abortAtom, comTip, diagnosticAtom, lispAtom, Random],
     DiagnosticsOps USING [calledByBye, DiagnosticsActivate],
     Display USING [Block, MeasureBlock, replaceFlags, Text, White],
     Environment USING [Block],
     -- Factor USING [],
     LispToolOps,
     Process,
     --Profile USING [SetUser],
     Runtime,
     String USING [AppendChar],
     System USING [GreenwichMeanTime],
     TemporaryBooting USING [BootButton],
     Time USING [Append, Current, Unpack, Unpacked],
     TIP USING [CreateClient, First, NotifyProc, Rest, Results],
     ToolFont USING [StringWidth],
     ToolWindow USING [
          Activate, AdjustProcType, Create, CreateSubwindow, Deactivate, Destroy,
          DisplayProcType, Show, TransitionProcType],
     UserInput USING [SetInputFocus],
     UserTerminal USING [hasBorder, screenHeight, screenWidth, SetBorder],
     Window USING [
          Box, Dims, GetChild, Handle, SetDisplayProc, Slide, ValidateTree],
     WindowFont USING [defaultFont, FontHeight, Handle];


ByeImplA: MONITOR
     IMPORTS
          ComSoftOps, DiagnosticsOps, Display, LispToolOps, 
	  Process, Runtime, String,
          TemporaryBooting, Time, TIP, ToolFont, ToolWindow, UserInput,
          UserTerminal, Window, WindowFont

     EXPORTS ByeOps =

     BEGIN OPEN DiagnosticsOps, LispToolOps;

     margin: CARDINAL = 4;
     toolWindow, subWindow: Window.Handle;
     swBox: Window.Box;
     running, deactivating, userAbort, dontBounce: BOOLEAN ← FALSE;
     wait: CONDITION ← [timeout: Process.SecondsToTicks[1]];
     stopped: CONDITION;

     Run: PROCEDURE =
          BEGIN
          doDeactivate: BOOLEAN ← FALSE;
          Go: ENTRY PROCEDURE = INLINE
               BEGIN
               ENABLE BEGIN UNWIND => NULL; ABORTED => CONTINUE; END;
               running ← TRUE;
               IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[377B, 377B];
               DO
                    WAIT wait;
                    IF deactivating OR userAbort THEN EXIT
                    ELSE
                         IF dontBounce THEN BEGIN END
                         ELSE
                              BEGIN
                              Process.Pause[Process.SecondsToTicks[3]];  -- pause for x seconds
                              PaintTime[Time.Current[], FALSE];
                              IF ComSoftOps.Random[2] # 0 THEN LOOP;
                              Window.Slide[
                                   subWindow, swBox.place ← [
                                   x: ComSoftOps.Random[
                                   UserTerminal.screenWidth - swBox.dims.w],
                                   y: ComSoftOps.Random[
                                   UserTerminal.screenHeight - swBox.dims.h]]];
                              [] ← Window.SetDisplayProc[
                                   subWindow, InternalDisplay];
                              Window.ValidateTree[];
                              [] ← Window.SetDisplayProc[subWindow, EntryDisplay];
                              END;
                    ENDLOOP;
               ToolWindow.Destroy[subWindow];
               subWindow ← NIL;
               running ← FALSE;
               IF UserTerminal.hasBorder THEN UserTerminal.SetBorder[210B, 42B];
               IF deactivating THEN NOTIFY stopped ELSE doDeactivate ← TRUE;
               END;
          userAbort ← FALSE;
          Go[];
          IF doDeactivate THEN
               BEGIN userAbort ← TRUE; [] ← ToolWindow.Deactivate[toolWindow]; END;
          END;

     StartBye: PROCEDURE = BEGIN Process.Detach[FORK Run]; END;

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

     InternalDisplay: INTERNAL ToolWindow.DisplayProcType =
          BEGIN PaintTime[Time.Current[], TRUE]; END;

     -- 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;
	  s0: STRING ← "***** INTERLISP-D ***** "L;
          s1: STRING ← [80];
          s2: STRING ← "Click Left-button for InstallLispTool"L;
          s3: STRING ← " Right-button for Diagnostics"L;
          s4: STRING ← " Both-buttons for ProfileTool"L;

          timeWidth: CARDINAL;
	  s0Width: CARDINAL ← StringWidth[s0, font];
          s2Width: CARDINAL ← StringWidth[s2, font];
          s3Width: CARDINAL ← StringWidth[s3, font];
          s4Width: CARDINAL ← StringWidth[s4, font];

          unp: Time.Unpacked ← Time.Unpack[time];
	  <<
          AppendDec2: PROCEDURE [n: CARDINAL] =
               BEGIN
               String.AppendChar[s1, '0 + n/10];
               String.AppendChar[s1, '0 + n MOD 10];
               END;
          AppendDec2[unp.hour];
          String.AppendChar[s1, ':];
          AppendDec2[unp.minute];
          String.AppendChar[s1, ':];
          AppendDec2[unp.second];
          timeWidth ← StringWidth[s1, font];
	  >>
	  Time.Append[s: s1, unpacked:unp, zone: TRUE];
	  timeWidth ← StringWidth[s1, 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;
               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.Block[
                    window: subWindow, block: dayBlock,
                    place: [
		     x: (swBox.dims.w - dayWidth)/2,
		     y: margin],
                    flags: Display.replaceFlags];
               END;
	       
          [] ← Display.Text[
               window: subWindow, string: s1,
               place: [
               x: (swBox.dims.w - timeWidth)/2,
               y: WindowFont.FontHeight[font] + margin+1],
               flags: Display.replaceFlags];

	  [] ← Display.Text[
               window: subWindow, string: s0,
               place: [
               x: (swBox.dims.w - s0Width)/2,
               y: WindowFont.FontHeight[font] + 4*margin],
               flags: Display.replaceFlags];

          [] ← Display.Text[
               window: subWindow, string: s2,
               place: [
               x: (swBox.dims.w - s2Width)/2,
               y: WindowFont.FontHeight[font] + 7*margin],
               flags: Display.replaceFlags];

          [] ← Display.Text[
               window: subWindow, string: s3,
               place: [
               x: (swBox.dims.w - s3Width)/2,
               y: WindowFont.FontHeight[font] + 10*margin],
               flags: Display.replaceFlags];

          [] ← Display.Text[
               window: subWindow, string: s4,
               place: [
               x: (swBox.dims.w - s4Width)/2,
               y: WindowFont.FontHeight[font] + 13*margin],
               flags: Display.replaceFlags];

          displayed ← [unp.second, unp.weekday];
          RETURN
          END;

     AdjustProc: ENTRY ToolWindow.AdjustProcType = BEGIN END;

     TransitionProc: ENTRY ToolWindow.TransitionProcType =
          BEGIN
          ENABLE UNWIND => NULL;
          SELECT TRUE FROM
               new = old =>
                    BEGIN
                    -- UserInput.SetInputFocus[subWindow, Nop, TRUE];
                    RETURN;
                    END;

               new = inactive => {
                    deactivating ← TRUE;
                    --UserInput.SetInputFocus[subWindow, Nop, TRUE];
                    NOTIFY wait;
                    WHILE running DO WAIT stopped ENDLOOP};

               old = inactive => {
                    subWindow ← ToolWindow.CreateSubwindow[
                         parent: window, display: EntryDisplay, box: swBox];
                    TIP.CreateClient[
                         window: Window.GetChild[window], table: ComSoftOps.comTip,
                         notify: TIPInterpreter];
                    TIP.CreateClient[
                         window: subWindow, table: ComSoftOps.comTip,
                         notify: TIPInterpreter];
                    deactivating ← FALSE;
                    IF ~running THEN StartBye[];
                    UserInput.SetInputFocus[subWindow, Nop, TRUE]}
               ENDCASE;
          END;

     Nop: PROC [Window.Handle, LONG POINTER] = {};

     TIPInterpreter: ENTRY TIP.NotifyProc =
          BEGIN

          FOR r: TIP.Results ← results, r.Rest UNTIL r = NIL DO
               WITH z: r.First SELECT FROM
                    atom =>
                         SELECT z.a FROM
                              ComSoftOps.abortAtom =>
                                   BEGIN
                                   --TemporaryBooting.BootButton[];
                                   --NOTIFY wait;
				   LispToolOps.ProfileToolActivate[];
                                   END;
                              ComSoftOps.diagnosticAtom =>
                                   BEGIN
                                   StopBouncing[];
                                   DiagnosticsOps.DiagnosticsActivate[];
                                   ResumeBouncing;
                                   END;
                              ComSoftOps.lispAtom =>
                                   BEGIN
                                   --ResumeBouncing;
                                   LispToolOps.LispToolActivate[];
                                   END;
                              ENDCASE;
                    ENDCASE;
               ENDLOOP;
          END;


     ByeActivate: PUBLIC PROCEDURE = BEGIN ToolWindow.Activate[toolWindow]; END;

     StopBouncing: PUBLIC PROCEDURE = BEGIN dontBounce ← TRUE; END;

     ResumeBouncing: PUBLIC PROCEDURE = BEGIN dontBounce ← FALSE; END;

     Init: PROCEDURE =
          BEGIN OPEN ToolFont;
          --swBox.dims.w ← StringWidth["Wednesday"L, WindowFont.defaultFont] + 2*margin;
          swBox.dims.w ←
               StringWidth[
                    "Click Left-button for InstallLispTool"L,
                    WindowFont.defaultFont] + 2*margin;

          swBox.dims.h ←
               2*WindowFont.FontHeight[WindowFont.defaultFont] + 13*margin + 2;
          swBox.place ← [0, 0];
          toolWindow ← ToolWindow.Create[
               name: ""L, adjust: AdjustProc, transition: TransitionProc,
               box: [
               place: [0, 0],
               dims: [w: UserTerminal.screenWidth, h: UserTerminal.screenHeight]],
               initialState: active, named: FALSE];
          TIP.CreateClient[
               window: toolWindow, table: ComSoftOps.comTip,
               notify: TIPInterpreter];
          TransitionProc[toolWindow, inactive, active];
          ToolWindow.Show[toolWindow];
          calledByBye ← TRUE;
          END;

     ByeStartTrap: PUBLIC PROC = {};

     Init[];

     END... Prog ByeImplA