home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / oberon / system / oberon.mod (.txt) < prev    next >
Oberon Text  |  1977-12-31  |  17KB  |  507 lines

  1. Syntax20b.Scn.Fnt
  2. ParcElems
  3. Alloc
  4. Syntax24b.Scn.Fnt
  5. Syntax10.Scn.Fnt
  6. Syntax10i.Scn.Fnt
  7. Syntax10b.Scn.Fnt
  8. (* AMIGA *)
  9. MODULE Oberon; (*JG 6.9.90*)    (* << RC 19.3.93, shml, cn 2.6.94 *)
  10.     IMPORT SYSTEM, Amiga, AmigaDos, Kernel, Modules, Input, Display, Fonts, Viewers, Texts, V24, AmigaIntuition;
  11.     CONST
  12.         (*message ids*)
  13.         consume* = 0; track* = 1; (* InputMsg *)
  14.         defocus* = 0; neutralize* = 1; mark* = 2; (* ControlMsg *)
  15.         BasicCycle = 20;
  16.         ESC = 1BX; SETUP = 0A4X;
  17.     TYPE
  18.         Painter* = PROCEDURE (x, y: INTEGER);
  19.         Marker* = RECORD Fade*, Draw*: Painter END;
  20.         Cursor* = RECORD
  21.             marker*: Marker; on*: BOOLEAN; X*, Y*: INTEGER
  22.         END;
  23.         ParList* = POINTER TO ParRec;
  24.         ParRec* = RECORD
  25.             vwr*: Viewers.Viewer;
  26.             frame*: Display.Frame;
  27.             text*: Texts.Text;
  28.             pos*: LONGINT
  29.         END;
  30.         InputMsg* = RECORD (Display.FrameMsg)
  31.             id*: INTEGER;
  32.             keys*: SET;
  33.             X*, Y*: INTEGER;
  34.             ch*: CHAR;
  35.             fnt*: Fonts.Font;
  36.             col*, voff*: SHORTINT
  37.         END;
  38.         SelectionMsg* = RECORD (Display.FrameMsg)
  39.             time*: LONGINT;
  40.             text*: Texts.Text;
  41.             beg*, end*: LONGINT
  42.         END;
  43.         ControlMsg* = RECORD (Display.FrameMsg)
  44.             id*, X*, Y*: INTEGER
  45.         END;
  46.         CopyOverMsg* = RECORD (Display.FrameMsg)
  47.             text*: Texts.Text;
  48.             beg*, end*: LONGINT
  49.         END;
  50.         CopyMsg* = RECORD (Display.FrameMsg)
  51.             F*: Display.Frame
  52.         END;
  53.         Task* = POINTER TO TaskDesc;
  54.         Handler* = PROCEDURE;
  55.         TaskDesc* = RECORD
  56.             next: Task;
  57.             safe*: BOOLEAN;
  58.             time*: LONGINT;
  59.             handle*: Handler
  60.         END;
  61.         User*: ARRAY 8 OF CHAR;
  62.         Password*: LONGINT;
  63.         Arrow*, Star*: Marker;
  64.         Mouse*, Pointer*: Cursor;
  65.         FocusViewer*: Viewers.Viewer;
  66.         Log*: Texts.Text;
  67.         Par*: ParList; (*actual parameters*)
  68.         CurTask*, PrevTask: Task;
  69.         CurFnt*: Fonts.Font; CurCol*, CurOff*: SHORTINT;
  70.         DW, DH, CL, H0, H1, H2, H3: INTEGER;
  71.         unitW: INTEGER;
  72.         ActCnt: INTEGER; (*action count for GC*)
  73.         Mod: Modules.Module;
  74.     (*user identification*)
  75.     PROCEDURE Code(VAR s: ARRAY OF CHAR): LONGINT;
  76.         VAR i: INTEGER; a, b, c: LONGINT;
  77.     BEGIN
  78.         a := 0; b := 0; i := 0;
  79.         WHILE s[i] # 0X DO
  80.             c := b; b := a; a := (c MOD 509 + 1) * 127 + ORD(s[i]);
  81.             INC(i)
  82.         END;
  83.         IF b >= 32768 THEN b := b - 65536 END;
  84.         RETURN b * 65536 + a
  85.     END Code;
  86.     PROCEDURE SetUser* (VAR user, password: ARRAY OF CHAR);
  87.     BEGIN COPY(user, User); Password := Code(password)
  88.     END SetUser;
  89.     (*clocks*)
  90.     PROCEDURE GetClock* (VAR t, d: LONGINT);
  91.     BEGIN Kernel.GetClock(t, d)
  92.     END GetClock;
  93.     PROCEDURE SetClock* (t, d: LONGINT);
  94.     BEGIN Kernel.SetClock(t, d)
  95.     END SetClock;
  96.     PROCEDURE Time* (): LONGINT;
  97.     BEGIN RETURN Input.Time()
  98.     END Time;
  99.     (*cursor handling*)
  100.     PROCEDURE FlipArrow (X, Y: INTEGER);
  101.     BEGIN
  102.         (*IF X < CL THEN *)
  103.             (*IF X > DW - 15 THEN X := DW - 15 END *)
  104.         (*ELSE *)
  105.             (*IF X > CL + DW - 15 THEN X := CL + DW - 15 END *)
  106.         (*END; *)
  107.         (*IF Y < 14 THEN Y := 14 ELSIF Y > DH THEN Y := DH END; *)
  108.         IF X < CL THEN X := CL ELSIF X > CL + DW-1 THEN X := CL + DW-1 END;
  109.         IF Y < 0 THEN Y := 0 ELSIF Y > DH THEN Y := DH END;
  110.         Display.CopyPattern(Display.white, Display.arrow, X, Y - 14, 2)
  111.     END FlipArrow;
  112.     PROCEDURE FlipStar (X, Y: INTEGER);
  113.     BEGIN
  114.         IF X < CL THEN
  115.             IF X < 7 THEN X := 7 ELSIF X > DW - 8 THEN X := DW - 8 END
  116.         ELSE
  117.             IF X < CL + 7 THEN X := CL + 7 ELSIF X > CL + DW - 8 THEN X := CL + DW - 8 END
  118.         END ;
  119.         IF Y < 7 THEN Y := 7 ELSIF Y > DH - 8 THEN Y := DH - 8 END;
  120.         Display.CopyPattern(Display.white, Display.star, X - 7, Y - 7, 2)
  121.     END FlipStar;
  122.     PROCEDURE OpenCursor* (VAR c: Cursor);
  123.     BEGIN c.on := FALSE; c.X := 0; c.Y := 0
  124.     END OpenCursor;
  125.     PROCEDURE FadeCursor* (VAR c: Cursor);
  126.     BEGIN IF c.on THEN c.marker.Fade(c.X, c.Y); c.on := FALSE END
  127.     END FadeCursor;
  128.     PROCEDURE DrawCursor* (VAR c: Cursor; VAR m: Marker; X, Y: INTEGER);
  129.     BEGIN
  130.         IF c.on & ((X # c.X) OR (Y # c.Y) OR (m.Draw # c.marker.Draw)) THEN
  131.             c.marker.Fade(c.X, c.Y); c.on := FALSE
  132.         END;
  133.         IF ~c.on THEN
  134.             m.Draw(X, Y); c.marker := m; c.X := X; c.Y := Y; c.on := TRUE
  135.         END
  136.     END DrawCursor;
  137.     (*display management*)
  138.     PROCEDURE RemoveMarks* (X, Y, W, H: INTEGER);
  139.     BEGIN
  140.         IF (Mouse.X > X - 16) & (Mouse.X < X + W + 16) & (Mouse.Y > Y - 16) & (Mouse.Y < Y + H + 16) THEN
  141.             FadeCursor(Mouse)
  142.         END;
  143.         IF (Pointer.X > X - 8) & (Pointer.X < X + W + 8) & (Pointer.Y > Y - 8) & (Pointer.Y < Y + H + 8) THEN
  144.             FadeCursor(Pointer)
  145.         END
  146.     END RemoveMarks;
  147.     PROCEDURE HandleFiller (V: Display.Frame; VAR M: Display.FrameMsg);
  148.     BEGIN
  149.         WITH V: Viewers.Viewer DO
  150.             IF M IS InputMsg THEN
  151.                 WITH M: InputMsg DO
  152.                     IF M.id = track THEN DrawCursor(Mouse, Arrow, M.X, M.Y) END
  153.                 END
  154.             ELSIF M IS ControlMsg THEN
  155.                  WITH M: ControlMsg DO
  156.                      IF M.id = mark THEN DrawCursor(Pointer, Star, M.X, M.Y) END
  157.                  END
  158.             ELSIF M IS Viewers.ViewerMsg THEN
  159.                 WITH M: Viewers.ViewerMsg DO
  160.                     IF (M.id = Viewers.restore) & (V.W > 0) & (V.H > 0) THEN
  161.                         RemoveMarks(V.X, V.Y, V.W, V.H);
  162.                         Display.ReplConst(Display.black, V.X, V.Y, V.W, V.H, 0)
  163.                     ELSIF (M.id = Viewers.modify) & (M.Y < V.Y) THEN
  164.                         RemoveMarks(V.X, M.Y, V.W, V.Y - M.Y);
  165.                         Display.ReplConst(Display.black, V.X, M.Y, V.W, V.Y - M.Y, 0)
  166.                     END
  167.                 END
  168.             END
  169.         END
  170.     END HandleFiller;
  171.     PROCEDURE OpenDisplay* (UW, SW, H: INTEGER);
  172.         VAR Filler: Viewers.Viewer;
  173.     BEGIN
  174.          Input.SetMouseLimits(Viewers.curW + UW + SW, H);
  175.          Display.ReplConst(Display.black, Viewers.curW, 0, UW + SW, H, 0);
  176.          NEW(Filler); Filler.handle := HandleFiller;
  177.          Viewers.InitTrack(UW, H, Filler); (*init user track*)
  178.          NEW(Filler); Filler.handle := HandleFiller;
  179.          Viewers.InitTrack(SW, H, Filler) (*init system track*)
  180.     END OpenDisplay;
  181.     PROCEDURE DisplayWidth* (X: INTEGER): INTEGER;
  182.     BEGIN RETURN DW
  183.     END DisplayWidth;
  184.     PROCEDURE DisplayHeight* (X: INTEGER): INTEGER;
  185.     BEGIN RETURN DH
  186.     END DisplayHeight;
  187.     PROCEDURE OpenTrack* (X, W: INTEGER);
  188.         VAR Filler: Viewers.Viewer;
  189.     BEGIN
  190.         NEW(Filler); Filler.handle := HandleFiller;
  191.         Viewers.OpenTrack(X, W, Filler)
  192.     END OpenTrack;
  193.     PROCEDURE UserTrack* (X: INTEGER): INTEGER;
  194.     BEGIN RETURN X DIV DW * DW
  195.     END UserTrack;
  196.     PROCEDURE SystemTrack* (X: INTEGER): INTEGER;
  197.     BEGIN RETURN X DIV DW * DW + DW DIV 8 * 5
  198.     END SystemTrack;
  199.     PROCEDURE UY (X: INTEGER): INTEGER;
  200.         VAR fil, bot, alt, max: Display.Frame;
  201.     BEGIN
  202.         Viewers.Locate(X, 0, fil, bot, alt, max);
  203.         IF fil.H >= DH DIV 8 THEN RETURN DH END;
  204.         RETURN max.Y + max.H DIV 2
  205.     END UY;
  206.     PROCEDURE AllocateUserViewer* (DX: INTEGER; VAR X, Y: INTEGER);
  207.     BEGIN
  208.         IF Pointer.on THEN X := Pointer.X; Y := Pointer.Y
  209.         ELSE X := DX DIV DW * DW; Y := UY(X)
  210.         END
  211.     END AllocateUserViewer;
  212.     PROCEDURE SY (X: INTEGER): INTEGER;
  213.         VAR fil, bot, alt, max: Display.Frame;
  214.     BEGIN
  215.         Viewers.Locate(X, DH, fil, bot, alt, max);
  216.         IF fil.H >= DH DIV 8 THEN RETURN DH END;
  217.         IF max.H >= DH - H0 THEN RETURN max.Y + H3 END;
  218.         IF max.H >= H3 - H0 THEN RETURN max.Y + H2 END;
  219.         IF max.H >= H2 - H0 THEN RETURN max.Y + H1 END;
  220.         IF max # bot THEN RETURN max.Y + max.H DIV 2 END;
  221.         IF bot.H >= H1 THEN RETURN bot.H DIV 2 END;
  222.         RETURN alt.Y + alt.H DIV 2
  223.     END SY;
  224.     PROCEDURE AllocateSystemViewer* (DX: INTEGER; VAR X, Y: INTEGER);
  225.     BEGIN
  226.         IF Pointer.on THEN X := Pointer.X; Y := Pointer.Y
  227.         ELSE X := DX DIV DW * DW + DW DIV 8 * 5; Y := SY(X)
  228.         END
  229.     END AllocateSystemViewer;
  230.     PROCEDURE MarkedViewer* (): Viewers.Viewer;
  231.     BEGIN RETURN Viewers.This(Pointer.X, Pointer.Y)
  232.     END MarkedViewer;
  233.     PROCEDURE PassFocus* (V: Viewers.Viewer);
  234.         VAR M: ControlMsg;
  235.     BEGIN M.id := defocus; FocusViewer.handle(FocusViewer, M); FocusViewer := V
  236.     END PassFocus;
  237.     (*command interpretation*)
  238.     PROCEDURE Call* (name: ARRAY OF CHAR; par: ParList; new: BOOLEAN; VAR res: INTEGER);
  239.         VAR Mod: Modules.Module; P: Modules.Command; i, j: INTEGER;
  240.     BEGIN
  241.         (*Amiga.Turbo; (* set task priority high *)*)     (*<<RD only MainLoop should change the Pri*)
  242.         res := 1;
  243.         i := 0; j := 0;
  244.         WHILE name[j] # 0X DO
  245.             IF name[j] = "." THEN i := j END;
  246.             INC(j)
  247.         END;
  248.         IF i > 0 THEN
  249.             name[i] := 0X;
  250.             IF new THEN Modules.Free(name, FALSE) END;
  251.             Mod := Modules.ThisMod(name);
  252.             IF Modules.res = 0 THEN
  253.                 INC(i); j := i;
  254.                 WHILE name[j] # 0X DO name[j - i] := name[j]; INC(j) END;
  255.                 name[j - i] := 0X;
  256.                 P := Modules.ThisCommand(Mod, name);
  257.                 IF Modules.res = 0 THEN
  258.                     Par := par; Par.vwr := Viewers.This(par.frame.X, par.frame.Y); P; res := 0
  259.                 ELSE
  260.                     res:=Modules.res
  261.                 END
  262.             ELSE res := Modules.res
  263.             END
  264.         END;
  265.         (*Amiga.Idle  (* set task priority low *)*)     (*<<RD only MainLoop should change the Pri*)
  266.     END Call;
  267.     PROCEDURE GetSelection* (VAR text: Texts.Text; VAR beg, end, time: LONGINT);
  268.         VAR M: SelectionMsg;
  269.     BEGIN
  270.         M.time := -1; Viewers.Broadcast(M); time := M.time;
  271.         IF time >= 0 THEN text := M.text; beg := M.beg; end := M.end END
  272.     END GetSelection;
  273.     PROCEDURE GC;
  274.     BEGIN
  275.         IF ActCnt<=0 THEN
  276.             Kernel.GC(TRUE);
  277.             ActCnt:=BasicCycle
  278.         END
  279.     END GC;
  280.     PROCEDURE Install* (T: Task);
  281.         VAR t: Task;
  282.     BEGIN t := PrevTask;
  283.         WHILE (t.next # PrevTask) & (t.next # T) DO t := t.next END;
  284.         IF t.next # T THEN T.next := PrevTask; t.next := T END
  285.     END Install;
  286.     PROCEDURE Remove* (T: Task);
  287.         VAR t: Task;
  288.     BEGIN t := PrevTask;
  289.         WHILE (t.next # T) & (t.next # PrevTask) DO t := t.next END;
  290.         IF t.next = T THEN t.next := t.next.next; PrevTask := t.next END;
  291.         IF CurTask = T THEN CurTask := PrevTask.next END
  292.     END Remove;
  293.     PROCEDURE Collect* (count: INTEGER);
  294.     BEGIN
  295.         ActCnt := count
  296.     END Collect;
  297.     PROCEDURE SetFont* (fnt: Fonts.Font);
  298.     BEGIN
  299.         CurFnt := fnt
  300.     END SetFont;
  301.     PROCEDURE SetColor* (col: SHORTINT);
  302.     BEGIN CurCol := col
  303.     END SetColor;
  304.     PROCEDURE SetOffset* (voff: SHORTINT);
  305.     BEGIN CurOff := voff
  306.     END SetOffset;
  307.     PROCEDURE NotifyTasks;    (* << JT *)
  308.         Call handler of all those task, which have set their time field to -1.
  309.         VAR t0, t1: Task;
  310.     BEGIN t0 := PrevTask;
  311.         REPEAT
  312.             CurTask := PrevTask.next;
  313.             IF CurTask.time = -1 THEN
  314.                 IF ~CurTask.safe THEN PrevTask.next := CurTask.next END;
  315.                 t1 := CurTask; CurTask.handle; PrevTask.next := CurTask;
  316.                 IF CurTask # t1 THEN RETURN END (*detect Remove(CurTask)*)
  317.             END;
  318.             PrevTask := CurTask
  319.         UNTIL CurTask = t0
  320.     END NotifyTasks;
  321.     PROCEDURE NotifyAllTasks;    (* << RD for Time depending MainLoop *)
  322.         Call handler of all those task, which have set their time field to -1.
  323.         VAR t0, t1: Task; ti: LONGINT;
  324.     BEGIN 
  325.         t0 := PrevTask;
  326.         ti:=Input.Time();
  327.         REPEAT
  328.             CurTask := PrevTask.next;
  329.             IF (CurTask.time <= ti) & (CurTask.time # -1) THEN
  330.                 IF ~CurTask.safe THEN PrevTask.next := CurTask.next END;
  331.                 t1 := CurTask; CurTask.handle; PrevTask.next := CurTask;
  332.                 IF CurTask # t1 THEN RETURN END (*detect Remove(CurTask)*)
  333.             END;
  334.             PrevTask := CurTask
  335.         UNTIL CurTask = t0
  336.     END NotifyAllTasks;
  337.     PROCEDURE Loop*;
  338.         The Oberon loop. The "task scheduler" of Oberon.
  339.         TYPE
  340.             winptr = POINTER TO AmigaIntuition.Window;
  341.         VAR
  342.             frame:RECORD END;
  343.             V: Viewers.Viewer; M: InputMsg; N: ControlMsg;
  344.             prevX, prevY, X, Y: INTEGER; keys: SET; ch: CHAR;
  345.             VM: Viewers.ViewerMsg;    (* << *)
  346.             LastLoopType: BOOLEAN;   (* <> *)
  347.             win: winptr;    (*<<RD*)
  348.         PROCEDURE HandleChar();    (*<RD*)
  349.             VAR
  350.                 chint: INTEGER;
  351.                 dumMod: Modules.Module;
  352.         BEGIN
  353.             Input.Read(ch);
  354.             chint:=ORD(ch);
  355.             IF ch = ESC THEN
  356.                 N.id := neutralize; Viewers.Broadcast(N); FadeCursor(Pointer)
  357.             ELSIF ch = SETUP THEN
  358.                 N.id := mark; N.X := X; N.Y := Y; V := Viewers.This(X, Y); V.handle(V, N)
  359.             ELSIF ch = 0CX THEN    (* << Form Feed => refresh display*)
  360.                 N.id := neutralize; Viewers.Broadcast(N); FadeCursor(Pointer);
  361.                 VM.id := Viewers.suspend; Viewers.Broadcast(VM);
  362.                 VM.id := Viewers.restore; Viewers.Broadcast(VM)
  363.             ELSIF (chint>245) & (chint<255) THEN    (*<RD  F6-F10, HELP and Clipboard-Keys *)
  364.                 IF (chint>251) & (Kernel.FKey[13]=NIL) THEN dumMod:=Modules.ThisMod("Clipboard") END;
  365.                 IF Kernel.FKey[chint-240]#NIL THEN Kernel.FKey[chint-240] END;
  366.             ELSIF ch = 0EFX THEN
  367.                 Amiga.Terminate
  368.             ELSE
  369.                 M.id := consume; M.ch := ch; M.fnt := CurFnt; M.col := CurCol; M.voff := CurOff;
  370.                 FocusViewer.handle(FocusViewer, M);
  371.                 DEC(ActCnt); NotifyTasks
  372.             END
  373.         END HandleChar;
  374.     BEGIN
  375.             Remember the current stack, so that the Kernel's stack collector knows where to look for pointers.
  376.         LastLoopType:=~Amiga.MainLoopType;            (* <> *)
  377.         Kernel.stackBottom := SYSTEM.ADR(frame);    (* << *)
  378.         prevX:=-1; prevY:=1;
  379.         win:=SYSTEM.VAL(winptr, Amiga.window);
  380.         LOOP
  381.             IF AmigaIntuition.windowActive IN win.flags THEN
  382.                 Input.Mouse(keys, X, Y);
  383.             ELSE
  384.                 X:=prevX; Y:=prevY; keys:={};
  385.             END;
  386.             IF Amiga.MainLoopType THEN (* Time depending MainLoop *)
  387.                 IF ~LastLoopType THEN Amiga.Turbo; LastLoopType:=TRUE END;
  388.                 IF Input.Available() > 0 THEN
  389.                     (*
  390.                         Handle all special characters, before handling the standard case.
  391.                     *)
  392.                     HandleChar();    (*<RD*)
  393.                 ELSIF keys # {} THEN
  394.                     (*
  395.                         As long, as a mouse key is pressed, send messages to the viewer on which the cursor
  396.                         is placed. Return to the loop only, when all mouse keys have been released.
  397.                     *)
  398.                     M.id := track; M.X := X; M.Y := Y; M.keys := keys;
  399.                     REPEAT
  400.                         V := Viewers.This(M.X, M.Y); V.handle(V, M);
  401.                         Input.Mouse(M.keys, M.X, M.Y)
  402.                     UNTIL M.keys = {};
  403.                     DEC(ActCnt); NotifyTasks
  404.                 ELSIF V24.Available() > 0 THEN
  405.                     (*
  406.                         Char available at the Serial Device => It is an event => notify ALL tasks
  407.                     *)
  408.                     NotifyTasks
  409.                 ELSE
  410.                     (*
  411.                         On mouse coordinate change notify the viewer below the actual mouse position.
  412.                     *)
  413.                     IF (X # prevX) OR (Y # prevY) OR ~Mouse.on THEN
  414.                         M.id := track; M.X := X; M.Y := Y; M.keys := {}; V := Viewers.This(X, Y);
  415.                         V.handle(V, M);
  416.                         prevX := X; prevY := Y
  417.                     END;
  418.                     (*
  419.                         Call handler of background task with a time not in the future and advance task pointer to next ready task.
  420.                         Tasks which are called by NotifiyTask (time=-1) are not called here.
  421.                     *)
  422.                     NotifyAllTasks
  423.                 END;
  424.                 Amiga.WaitTime(0, Amiga.TicsToWait); (* Wait for a while *)    
  425.             ELSE (* ever running MainLoop, low Task-Pri *)
  426.                     (* This is the way nearer the original *)
  427.                 IF LastLoopType THEN Amiga.Idle; LastLoopType:=FALSE END;
  428.                 IF Input.Available() > 0 THEN
  429.                     (*
  430.                         Handle all special characters, before handling the standard case.
  431.                     *)
  432.                     Amiga.Turbo;
  433.                     HandleChar();    (*<RD*)
  434.                     Amiga.Idle
  435.                 ELSIF keys # {} THEN
  436.                     (*
  437.                         As long, as a mouse key is pressed, send messages to the viewer on which the cursor
  438.                         is placed. Return to the loop only, when all mouse keys have been released.
  439.                     *)
  440.                     Amiga.Turbo;
  441.                     M.id := track; M.X := X; M.Y := Y; M.keys := keys;
  442.                     REPEAT
  443.                         V := Viewers.This(M.X, M.Y); V.handle(V, M);
  444.                         Input.Mouse(M.keys, M.X, M.Y)
  445.                     UNTIL M.keys = {};
  446.                     DEC(ActCnt); NotifyTasks;
  447.                     Amiga.Idle
  448.                 ELSIF V24.Available() > 0 THEN
  449.                     (*
  450.                         Char available at the Serial Device => It is an event => notify ALL tasks
  451.                     *)
  452.                     NotifyTasks
  453.                 ELSE
  454.                     (*
  455.                         On mouse coordinate change notify the viewer below the actual mouse position.
  456.                     *)
  457.                     IF (X # prevX) OR (Y # prevY) OR ~Mouse.on THEN
  458.                         Amiga.Turbo;
  459.                         M.id := track; M.X := X; M.Y := Y; M.keys := {}; V := Viewers.This(X, Y);
  460.                         V.handle(V, M);
  461.                         prevX := X; prevY := Y;
  462.                         Amiga.Idle
  463.                     END;
  464.                     (*
  465.                         Call handler of background task with a time not in the future and advance task pointer to next ready task.
  466.                         Tasks which are called by NotifiyTask (time=-1) are not called here.
  467.                     *)
  468.                     CurTask := PrevTask.next;
  469.                     IF (CurTask.time <= Input.Time()) & (CurTask.time # -1) THEN
  470.                         IF ~CurTask.safe THEN PrevTask.next := CurTask.next END;
  471.                         CurTask.handle; PrevTask.next := CurTask
  472.                     END;
  473.                     PrevTask := CurTask
  474.                 END
  475.             END
  476.         END
  477.     END Loop;
  478.     PROCEDURE Init;
  479.     BEGIN
  480.         User[0] := 0X;
  481.         Arrow.Fade := FlipArrow; Arrow.Draw := FlipArrow;
  482.         Star.Fade := FlipStar; Star.Draw := FlipStar;
  483.         OpenCursor(Mouse); OpenCursor(Pointer);
  484.         DW := Display.Width; DH := Display.Height; CL := Display.ColLeft;
  485.         H3 := DH - DH DIV 3;
  486.         H2 := H3 - H3 DIV 2;
  487.         H1 := DH DIV 5;
  488.         H0 := DH DIV 10;
  489.         unitW := DW DIV 8;
  490.         OpenDisplay(unitW * 5, unitW * 3, DH);
  491.         FocusViewer := Viewers.This(0, 0);
  492.         CurFnt := Fonts.Default;
  493.         CurCol := Display.white;
  494.         CurOff := 0;
  495.         Collect(BasicCycle);
  496.         NEW(PrevTask);
  497.         PrevTask.handle := GC;
  498.         PrevTask.safe := TRUE;
  499.         PrevTask.time := -1;    (* << (instead of 0) JT *)
  500.         PrevTask.next := PrevTask;
  501.         Display.SetMode(0, {})
  502.     END Init;
  503. BEGIN Init;
  504.     (* only if System not in boot file: *)
  505.     Mod:=Modules.ThisMod("System")
  506. END Oberon.
  507.