home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / ircle 1.5.1 / source / ircle sources / ApplBase.pas next >
Encoding:
Pascal/Delphi Source File  |  1993-01-16  |  11.9 KB  |  516 lines  |  [TEXT/PJMM]

  1. {    ApplBase - Event dispatcher    }
  2. {    File:    ApplBase, version 2.0.2    }
  3. {    Copyright © 1991-1992 Olaf Titz (s_titz@ira.uka.de)    }
  4.  
  5. {    This program is free software; you can redistribute it and/or modify    }
  6. {    it under the terms of the GNU General Public License as published by    }
  7. {    the Free Software Foundation; either version 2 of the License, or    }
  8. {    (at your option) any later version.    }
  9.  
  10. {    This program is distributed in the hope that it will be useful,    }
  11. {    but WITHOUT ANY WARRANTY; without even the implied warranty of    }
  12. {    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    }
  13. {    GNU General Public License for more details.    }
  14.  
  15. {    You should have received a copy of the GNU General Public License    }
  16. {    along with this program; if not, write to the Free Software    }
  17. {    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.    }
  18.  
  19. unit ApplBase;
  20.  
  21. interface
  22.  
  23. uses
  24.     Coroutines, 
  25.  
  26. {$IFC DISTRIBUTION }
  27. {$SETC TRACE=FALSE }
  28. {$ENDC }
  29.  
  30. {$IFC UseTCP}
  31.  
  32.     TCPTypes, TCPStuff, TCPConnections;
  33.  
  34. { If the compiler option UseTCP is set: }
  35. { This version cooperates with Peter Lewis' TCPConnections package. }
  36. { ConnectionEvents are treated just like regular events, having a priority }
  37. { dynamically changing from between key and update to lower. }
  38.  
  39. {$ENDC}
  40.  
  41. const
  42.     mouseMsg = 16;        { new 'events': mouseMsg+x, x=FindWindow result }
  43.     dialogMsg = 26;        { dialog: message=DialogPtr, item in theItem }
  44. {$IFC UseTCP}
  45.     TCPMsg = 27;        { Ptr to connectionEventRecord in message }
  46. {$ENDC}
  47.     menuMsg = -226;    { menuMsg+x, x=menu ID; menuBar=30 }
  48.  
  49.     menuBar = 256;        { res ID of MBAR }
  50.     appleMenu = 256;    { res ID of MENU: apple,file,edit }
  51.     FileMenu = 257;        { apple and edit menu are mandatory }
  52.     EditMenu = 258;
  53.  
  54. var
  55.     theItem: integer;                { item hit in dialog boxes }
  56.     RunningInCoroutine: boolean;    { if coroutine other than global active }
  57.     HighCoPriority: boolean;        { if Coroutines should run more often }
  58.     WNETime: integer;            { Timeout parameter for WaitNextEvent }
  59. {$IFC UseTCP}
  60.     maxTCPFlood: integer;        { max n of consecutive TCP events }
  61. {$ENDC}
  62.  
  63. { If you define the compile option TRACE to true, a file 'ApplBase Trace' }
  64. { will be generated on each run which records events, context switches etc. }
  65. { Refer to the source below for details. }
  66.  
  67. {$IFC TRACE}
  68.     trace: text;
  69. {$ENDC}
  70.  
  71. procedure ApplEvents (var e: EventRecord);
  72. { Process given event }
  73.  
  74. procedure ApplInit;
  75. { Init the package }
  76.  
  77. procedure ApplRun;
  78. { Get event and process it }
  79.  
  80. procedure ApplExitProc (p: ProcPtr);
  81. { install exitproc }
  82.  
  83. procedure ApplExit;
  84. { call exitprocs & exit program }
  85.  
  86. function ApplTask (mytask: ProcPtr; message: integer): integer;
  87. { Enqueue task }
  88.  
  89. procedure ApplUntask (n: integer);
  90. { Dequeue task }
  91.  
  92. {    Task declaration:   function mytask(var e:EventRecord):boolean    }
  93. {    should return true if event completely processed    }
  94. {    The following has been done on task entry: Current grafport saved,    }
  95. {    grafport set to whatever appropriate on events for windows (mouse,update,activ.)    }
  96. {    all processing of DAs (SystemEdit...) and dialog events    }
  97.  
  98. function ApplCoroutine (mytask: ProcPtr; wspsize: integer): integer;
  99. { Start Coroutine in background, i.e. on null events }
  100.  
  101. function ApplWaitPB (pb: ParmBlkPtr): integer;
  102. { Wait for completion of async FileMgr call in background }
  103.  
  104.  
  105. implementation
  106.  
  107. const
  108.     NMSGS = 40;         { this means max. 10 menus }
  109.  
  110. type
  111.     EvtQuPtr = ^EvtQuRec;    { Event handler queue }
  112.     EvtQuRec = record
  113.             qLink: EvtQuPtr;
  114.             taskID: integer;
  115.             eProc: ProcPtr
  116.         end;
  117.  
  118.     BkQuPtr = ^BkQuRec;        { Background procs queue }
  119.     BkQuRec = record
  120.             qLink: BkQuPtr;
  121.             WSP: handle
  122.         end;
  123.  
  124.     ExQuPtr = ^ExQuRec;        { Exitproc queue }
  125.     ExQuRec = record
  126.             qLink: ExQuPtr;
  127.             eProc: ProcPtr
  128.         end;
  129.  
  130. var
  131.     EvtQuHdr: array[0..NMSGS] of EvtQuPtr;
  132.     EvtTID: integer;
  133.     ThisBack, LastBack: BkQuPtr;
  134.     ExitQuHdr: ExQuPtr;
  135.     applMItems: integer;
  136.     WindowDragRect: Rect;
  137.     univRgn: RgnHandle;
  138. {$IFC UseTCP}
  139.     TCPFlood: integer;
  140. {$ENDC}
  141.  
  142. function ECALL (var e: EventRecord; p: ProcPtr): boolean;
  143. inline
  144.     $205F, $4E90;        { movea.l (a7)+,a0; jsr (a0) }
  145.  
  146.  
  147. procedure ApplEvents (var e: EventRecord);
  148.     var
  149.         i: integer;
  150.         p, p0: WindowPtr;
  151.         l: EvtQuPtr;
  152.     begin
  153.         GetPort(p0);
  154.         if (e.what = keyDown) and (BitAnd(e.modifiers, cmdKey) <> 0) then begin
  155.             e.message := MenuKey(chr(e.message mod 256));  { Menu shortcut.. }
  156.             e.what := menuMsg
  157.         end
  158.         else if (e.what >= 0) and (e.what <= 15) then
  159.             if IsDialogEvent(e) then begin
  160. {$IFC TRACE}
  161.                 write(trace, 'D');
  162. {$ENDC}
  163.                 if (e.what = keyDown) and ((BitAnd(loword(e.message), 255) = 3) or (BitAnd(loword(e.message), 255) = 13)) then begin
  164.                     e.what := dialogMsg;    { Pressing Return or Enter in dialog... }
  165.                     e.message := longint(FrontWindow);
  166.                     theItem := 0            { is reported as Item #0 }
  167.                 end
  168.                 else if DialogSelect(e, p, theItem) then begin
  169.                     e.what := dialogMsg;        { Let the Dialog Mgr process the event... }
  170.                     e.message := longint(p)        { and report which dialog and item }
  171.                 end
  172.                 else if e.what <> 0 then
  173.                     exit(ApplEvents);            { DialogSelect has completely processed }
  174.             end;
  175.         if e.what = mouseDown then begin
  176.             i := FindWindow(e.where, p);
  177.             case i of
  178.                 inSysWindow: 
  179.                     begin
  180.                     if p = FrontWindow then
  181.                         SystemClick(e, p)
  182.                     else
  183.                         SelectWindow(p);
  184.                     exit(ApplEvents)
  185.                 end;
  186.                 inMenuBar: 
  187.                     begin
  188.                     e.message := MenuSelect(e.where);
  189.                     e.what := menuMsg
  190.                 end;
  191.                 otherwise
  192.                     if ((i = inContent) or (i = inGrow)) and (p <> FrontWindow) then begin
  193.                         SelectWindow(p);    { if click in non-active window, select it.. }
  194.                         exit(ApplEvents)
  195.                     end
  196.                     else begin
  197.                         SetPort(p);    { the window where the click is in }
  198.                         e.what := mouseMsg + i;
  199.                         e.message := longint(p)
  200.                     end
  201.             end;
  202.         end;
  203.         if e.what = menuMsg then begin    { Split the menu message }
  204. {$IFC TRACE}
  205.             write(trace, 'M');
  206. {$ENDC}
  207.             if HiWord(e.message) = 0 then
  208.                 e.what := 0
  209.             else begin
  210.                 e.what := menuMsg + HiWord(e.message);    { menuMsg+menuNo }
  211.                 e.message := LoWord(e.message);            { itemNo }
  212.                 if e.what = menuMsg + EditMenu then
  213.                     if SystemEdit(e.message - 1) then        { handle edit in DA }
  214.                         exit(ApplEvents)
  215.             end
  216.         end;
  217.         if (e.what = updateEvt) or (e.what = activateEvt) then
  218.             SetPort(WindowPtr(e.message));
  219.         l := EvtQuHdr[e.what];
  220.         while l <> nil do
  221.             with l^ do begin    { Call tasks }
  222.                 if ECALL(e, eProc) then
  223.                     leave;
  224.                 l := qLink
  225.             end;
  226.         HiliteMenu(0);
  227.         SetPort(p0);
  228.     end;
  229.  
  230.  
  231.  
  232. { --- Standard tasks --- }
  233.  
  234. function Accessories (var e: EventRecord): boolean; { menuMsg+appleMenu }
  235.     var
  236.         s: str255;
  237.         i: integer;
  238.     begin
  239.         if e.message > applMItems then begin                            { DA item selected? }
  240.             GetItem(GetMHandle(appleMenu), LoWord(e.message), s);    { Open it }
  241.             i := OpenDeskAcc(s);
  242.         end;
  243.         Accessories := true;
  244.     end;
  245.  
  246.  
  247. function AccessoryActivate (var e: EventRecord): boolean; {activateEvt }
  248.     var
  249.         p: WindowPeek;
  250.         m: MenuHandle;
  251.         i: integer;
  252.     begin
  253.         p := WindowPeek(e.message);
  254.         if p^.windowKind < 0 then begin    { DA window selected? }
  255.             if BitAnd(e.modifiers, activeFlag) <> 0 then begin
  256.                 m := GetMHandle(EditMenu);    { Yes -> enable Edit menu and }
  257.                 for i := 0 to 6 do                { standard Edit options }
  258.                     EnableItem(m, i);
  259.                 DisableItem(m, 2);                { but not the separator }
  260.             end
  261.             else
  262.                 InitCursor;                    { DA window deselected? -> reset the mouse cursor }
  263.         end;
  264.         AccessoryActivate := true;
  265.     end;
  266.  
  267.  
  268. function WindowDragging (var e: EventRecord): boolean;
  269.     begin
  270.         DragWindow(WindowPtr(e.message), e.where, WindowDragRect);
  271.         WindowDragging := true;
  272.     end;
  273.  
  274.  
  275. function CancelUpdates (var e: EventRecord): boolean;
  276.     begin
  277.         BeginUpdate(WindowPtr(e.message));    { Purge update events that have not been processed }
  278.         EndUpdate(WindowPtr(e.message));
  279.         CancelUpdates := true
  280.     end;
  281.  
  282. function BackgroundRun (var e: EventRecord): boolean;
  283.     begin
  284.         if ThisBack <> nil then begin
  285.             RunningInCoroutine := true;
  286.             Transfer(GlobalProc, ThisBack^.WSP);
  287.             RunningInCoroutine := false;
  288.             if GetHandleSize(ThisBack^.WSP) <= 0 then
  289.                 if LastBack = ThisBack then begin
  290.                     LastBack := nil;
  291.                     dispose(ThisBack);
  292.                     ThisBack := nil
  293.                 end
  294.                 else begin
  295.                     LastBack^.qLink := ThisBack^.qLink;
  296.                     dispose(ThisBack);
  297.                     ThisBack := LastBack^.qLink
  298.                 end
  299.             else begin
  300.                 LastBack := ThisBack;
  301.                 ThisBack := ThisBack^.qLink
  302.             end
  303.         end;
  304. {$IFC TRACE}
  305.         write(trace, 'B');
  306. {$ENDC}
  307.         BackgroundRun := true
  308.     end;
  309.  
  310.  
  311. function ApplTask (mytask: ProcPtr; message: integer): integer;
  312.     var
  313.         p: EvtQuPtr;
  314.     begin
  315.         EvtTID := EvtTID + 1;
  316.         new(p);
  317.         if p = nil then begin
  318. {$IFC TRACE}
  319.             write(trace, 'Failed ');
  320. {$ENDC}
  321.             ApplTask := -1
  322.         end
  323.         else
  324.             with p^ do begin
  325.                 ApplTask := EvtTID;
  326.                 qLink := EvtQuHdr[message];
  327.                 taskID := EvtTID;
  328.                 eProc := mytask;
  329.                 EvtQuHdr[message] := p;
  330.             end;
  331. {$IFC TRACE}
  332.         writeln(trace, 'ApplTask: ', mytask, message, EvtTID);
  333. {$ENDC}
  334.     end;
  335.  
  336.  
  337.  
  338. procedure ApplUntask (n: integer);
  339.     var
  340.         p, p0: EvtQuPtr;
  341.         i: integer;
  342.     begin
  343. {$IFC TRACE}
  344.         writeln(trace, 'ApplUntask ', n);
  345. {$ENDC}
  346.         for i := 0 to NMSGS do begin
  347.             p := EvtQuHdr[i];
  348.             if p <> nil then begin
  349.                 if p^.taskID = n then begin
  350.                     EvtQuHdr[i] := p^.qLink;
  351.                     exit(ApplUntask)
  352.                 end
  353.                 else
  354.                     repeat
  355.                         p0 := p;
  356.                         p := p0^.qLink;
  357.                         if p = nil then
  358.                             leave;
  359.                         if p^.taskID = n then begin
  360.                             p0^.qLink := p^.qLink;
  361.                             dispose(p);
  362.                             exit(ApplUntask)
  363.                         end;
  364.                     until false;
  365.             end
  366.         end;
  367.     end;
  368.  
  369.  
  370.  
  371. function ApplCoroutine (mytask: ProcPtr; wspsize: integer): integer;
  372.     var
  373.         h: Handle;
  374.         p: BkQuPtr;
  375.     begin
  376.         h := Newprocess(mytask, wspsize);
  377.         ApplCoroutine := MemError;
  378. {$IFC TRACE}
  379.         writeln(trace, 'ApplCoroutine ', mytask, wspsize, MemError);
  380. {$ENDC}
  381.         if h <> nil then begin
  382.             New(p);
  383.             if p = nil then begin
  384.                 DisposHandle(h);
  385.                 ApplCoroutine := MemError
  386.             end
  387.             else begin
  388.                 if LastBack <> nil then
  389.                     LastBack^.qLink := p;
  390.                 LastBack := p;
  391.                 if ThisBack = nil then
  392.                     ThisBack := p;
  393.                 p^.qLink := ThisBack;
  394.                 p^.WSP := h;
  395.             end
  396.         end
  397.     end;
  398.  
  399.  
  400.  
  401.  
  402. procedure ApplInit;
  403.     var
  404.         m: MenuHandle;
  405.         h: Handle;
  406.         p: GrafPtr;
  407.         i: integer;
  408.     begin
  409. {$IFC TRACE}
  410.         rewrite(trace, 'ApplBase Trace');
  411. {$ENDC}
  412.         for i := 0 to NMSGS do
  413.             EvtQuHdr[i] := nil;
  414.         ThisBack := nil;
  415.         LastBack := nil;
  416.         ExitQuHdr := nil;
  417.         RunningInCoroutine := false;
  418.         HighCoPriority := false;
  419.         WNETime := 10;
  420.         EvtTID := 0;
  421. {$IFC UseTCP}
  422.         TCPFlood := 0;
  423.         maxTCPFlood := 5;
  424. {$ENDC}
  425.         GetWMgrPort(p);
  426.         WindowDragRect := p^.portRect;
  427.         WindowDragRect.top := WindowDragRect.top + 20;
  428.         InsetRect(WindowDragRect, 4, 4);
  429.         univRgn := NewRgn;
  430.         SetRectRgn(univRgn, -32767, -32767, 32767, 32767);
  431.         h := GetNewMBar(menuBar);
  432.         SetMenuBar(h);
  433.         DrawMenuBar;
  434.         m := GetMHandle(appleMenu);
  435.         applMItems := CountMItems(m);
  436.         AddResMenu(m, 'DRVR');
  437.         i := ApplTask(@BackgroundRun, nullEvent);
  438.         i := ApplTask(@CancelUpdates, updateEvt);
  439.         i := ApplTask(@Accessories, menuMsg + appleMenu);
  440.         i := ApplTask(@AccessoryActivate, activateEvt);
  441.         i := ApplTask(@WindowDragging, mouseMsg + inDrag);
  442.         FlushEvents(everyEvent, 0);
  443.     end;
  444.  
  445.  
  446. procedure ApplRun;
  447.     var
  448.         e: EventRecord;
  449.         connEvt: ConnectionEventRecord;
  450.         b: Boolean;
  451.     begin
  452.         if RunningInCoroutine then begin
  453. {$IFC TRACE}
  454.             write(trace, 'G');
  455. {$ENDC}
  456.             Transfer(ThisBack^.WSP, GlobalProc)
  457.         end
  458.         else begin
  459. {$IFC TRACE}
  460.             write(trace, 'W');
  461. {$ENDC}
  462.             b := WaitNextEvent(-1, e, WNETime, univRgn);
  463. {$IFC UseTCP}
  464.             if (e.what = nullEvent) or (e.what = updateEvt) then
  465.                 if TCPFlood < maxTCPFlood then
  466.                     if GetConnectionEvent(any_connection, connEvt) then begin
  467. {$IFC TRACE}
  468.                         write(trace, 'C', ord(connEvt.event) : 2);
  469. {$ENDC}
  470.                         e.what := TCPMsg;
  471.                         e.message := longint(@ConnEvt);
  472.                         TCPFlood := TCPFlood + 1
  473.                     end
  474.                     else
  475.                         TCPFlood := 0
  476.                 else
  477.                     TCPFlood := 0;
  478. {$ENDC UseTCP}
  479.             ApplEvents(e);
  480.             if HighCoPriority then
  481.                 b := BackgroundRun(e);
  482.         end;
  483.     end;
  484.  
  485.  
  486. procedure ApplExitProc (p: ProcPtr);
  487.     var
  488.         e: ExQuPtr;
  489.     begin
  490.         new(e);
  491.         e^.qLink := ExitQuHdr;
  492.         e^.eProc := p;
  493.         ExitQuHdr := e;
  494.     end;
  495.  
  496. procedure CALL (p: ProcPtr);
  497. inline
  498.     $205F, $4E90;        { movea.l (a7)+,a0; jsr (a0) }
  499.  
  500. procedure ApplExit;
  501.     var
  502.         ep: ExQuPtr;
  503.     begin
  504.         ExitCoroutines;
  505.         ep := ExitQuHdr;
  506.         while ep <> nil do begin
  507.             CALL(ep^.eProc);
  508.             ep := ep^.qLink
  509.         end;
  510. {$IFC TRACE}
  511.         close(trace);
  512. {$ENDC}
  513.         halt;
  514.     end;
  515.  
  516. end.