(*(**********************************************************************

:Program.    AppPorts.mod
:Contents.   class for port handling Workbench App...-objects
:Author.     hartmut Goebel [hG]
:Copyright.  Copyright © 1992,1993 by hartmut Goebel
:Copyright.  for further information see PortHandle.doc
:Language.   Oberon-2
:Translator. Amiga Oberon V3.0
:Version.    $VER: AppPorts.mod 2.0 (2.7.93) Copyright © 1992,1993 by hartmut Goebel

(* $StackChk- $NilChk- $RangeChk- $CaseChk- $OvflChk- $ReturnChk- $ClearVars- *)
***********************************************************************)*)

MODULE AppPorts;

IMPORT
  d * := Dos,
  e := Exec,
  I *:= Intuition,
  Ports *,
  u * := Utility,
  wb* := Workbench;

CONST
  versionString = "$VER: AppPorts 2.0 (2.7.93) Copyright © 1992,1993 by hartmut Goebel";

TYPE
  AppPort * = POINTER TO AppPortDesc;
  AppPortDesc * = RECORD (Ports.PortDesc)
    quit * : BOOLEAN;
  END;

(****** AppPorts/--background-- ***********************
*
*  This class does not implement any of the AddApp...() or
*  RemoveApp...() functions, since this would be quite useless and
*  inefficient. Instead use the functions provided by Workbench.
*
*  Even if the class handles Workbench objects it does not check if
*  workbench.library has been opened succesfully since it does not
*  use any of the workbench.libraries functions.
*
*  SEE ALSO
*        wb/AddAppIconA(), wb/RemoveAppIcon(),
*        wb/AddAppMenuItemA(), wb/RemoveAppMenuItem(),
*        wb/AddAppWindowA(), wb/RemoveAppWindow(),
*
*****)

(****** AppPorts/Init ***********************************************
*
*   NAME
*       Init -- initialize AppPort
*
*   SYNOPSIS
*       Init (VAR ap: AppPortDesc): BOOLEAN;
*
*   FUNCTION
*       Creates a message port and enters it to AppPort.port.
*
*   INPUTS
*       ap  - AppPort to be initialized
*
*   RESULT
*       FALSE if the message port couldn't be created
*
**********)

PROCEDURE Init * (VAR ap: AppPortDesc): BOOLEAN;
BEGIN
  ap.quit := FALSE;
  RETURN Ports.Init(ap);
END Init;


(****** AppPorts/--abstract_handle_methods-- ***********************
*
*   There is an abstract method for each application object usable in
*   AmigaOS V37. AppPort.Handle() can only dispatch to one of this
*   methods.
*
*   SYNOPSIS
*       (VAR ap: AppPortDesc) HandleWindow   (VAR msg: wb.AppMessagePtr);
*       (VAR ap: AppPortDesc) HandleIcon     (VAR msg: wb.AppMessagePtr);
*       (VAR ap: AppPortDesc) HandleMenuItem (VAR msg: wb.AppMessagePtr);
*
*   FUNCTION
*       ** none, abstract method **
*       should become redefined by a concrete method by subclasses.
*
*   INPUTS
*       msg - IntuiMessage to be handled
*
*   RESULT
*       msg - NIL if method already relpied the message, else -unchanged-
*
*   SEE ALSO
*       AppPort.Handle()
*
**********)

PROCEDURE (VAR ap: AppPortDesc) HandleWindow * (VAR msg: wb.AppMessagePtr);
BEGIN HALT(20); END HandleWindow;

PROCEDURE (VAR ap: AppPortDesc) HandleIcon * (VAR msg: wb.AppMessagePtr);
BEGIN HALT(20); END HandleIcon;

PROCEDURE (VAR ap: AppPortDesc) HandleMenuItem * (VAR msg: wb.AppMessagePtr);
BEGIN HALT(20); END HandleMenuItem;


(****** AppPorts/AppPort.Handle *******************************
*
*   NAME
*       AppPort.Handle -- handle message dispatching (method)
*
*   SYNOPSIS
*       (VAR ip: AppPortDesc) Handle ();
*
*   FUNCTION
*       Gets a AppMessage from the AppPort, dispatches to the
*       handle method according to its type and replies the message
*       (if not already done by the method).
*
*       This will loop until there is no message pending or ip.quit
*       is TRUE.
*
*       A concrete handle method indicates that the message has already
*       been replied by setting it's parameter <msg> to NIL
*
*   EXAMPLE
*       TYPE
*         MyPort = RECORD (AppPortDesc) (*...*) END;
*       VAR
*         myport: MyPort;
*
*       PROCEDURE (VAR mp: MyPort) HandleWindow * (VAR msg: wb.AppMessagePtr);
*       (* will take some time, so let's reply() the msg *)
*       BEGIN
*         (* save values *)
*         ...
*         mp.ReplyMsg(msg);
*         msg := NIL;  (* so MyPort.Handle doesn't reply it *)
*         (* handle with saved value *)
*         ...
*       END HandleWindow;
*       ...
*
*       WHILE ~ myport.quit DO
*         Exec.WaitPort(myport.port);
*         myport.handle();
*       END;
*       ...
*
*   SEE ALSO
*       Init(), --abstract_handle_methods--
*
********)

PROCEDURE (VAR ap: AppPortDesc) Handle * ();
VAR
  msg: wb.AppMessagePtr;
BEGIN
  LOOP
    msg := e.GetMsg(ap.port);
    IF msg = NIL THEN EXIT; END;
    CASE msg.type OF
    | wb.appWindow  : ap.HandleWindow(msg);
    | wb.appIcon    : ap.HandleIcon(msg);
    | wb.appMenuItem: ap.HandleMenuItem(msg);
    ELSE END;
    IF msg # NIL THEN e.ReplyMsg(msg); END;
    IF ap.quit THEN EXIT; END;
  END;
END Handle;

END AppPorts.
