home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 144.lha / VScreen_Src / vScreen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-21  |  14.0 KB  |  389 lines

  1. /*
  2.  *  VSCREEN.C       Creates virtual screens that can be larger than
  3.  *                  the actual display area of your monitor.  The virtual
  4.  *                  screen scrolls when the mouse moves off the edge of
  5.  *                  the display.
  6.  *
  7.  *                  Copyright 1988 by Davide P. Cervone, all rights reserved.
  8.  *
  9. --MORE--(4%) *                  You may may distibute this code as is, for non-commercial
  10.  *                  purposes, provided that this notice remains intact and the
  11.  *                  documentation file is distributed with it.
  12.  *
  13.  *                  You may not modify this code or incorporate it into your
  14.  *                  own programs without the permission of the author.
  15.  */
  16. /*
  17.  *  WARNING:  This code uses and even modifies the INTUITIONPRIVATE
  18.  *  area of the IntuitionBase structure.  Use it at your own risk.  It is
  19.  *  likely to break under a future release of Intuition.
  20.  */
  21. #include "vScreen.h"
  22. static char *program = "vScreen";           /* the program name */
  23. static char *author  = COPYRIGHT;           /* the copyright notice */
  24. #define LOADVERS        1                   /* this program's version */
  25. static char *handler = "L:vScreen-Handler"; /* the name of the handler */
  26. #define HANDLER         &(handler[2])       /* same but in the current dir */
  27. --MORE--(6%)
  28. extern struct LayersBase *LayersBase;       /* the Layers library */
  29.  
  30. struct vScreenInfo *vScreenData;            /* data needed by the handler */
  31. struct Screen *VScreen = NULL;              /* the virtual screen */
  32. static long Segment = NULL;                 /* the loaded handler */
  33. SHORT ScreenWidth,ScreenHeight;             /* the new screen sizes */
  34. static struct MsgPort *NamedPort = NULL;    /* used to find the handler later */static struct MsgPort *InputPort = NULL;    /* to talk to Input.Device */
  35. static struct IOStdReq *InputBlock = NULL;  /* IO block for Input.Device */
  36. static short  InputDevice = FALSE;          /* is Input.Device open? */
  37. static int    Enlarged = FALSE;             /* is screen changed? */
  38. /*
  39.  *  These routines are in vScreenSetup.c
  40.  */
  41. extern struct Screen *FindScreen();
  42. extern void SetVariables();
  43. extern void GetVariables();
  44. extern int  EnlargeScreen();
  45. --MORE--(9%)extern void RestoreScreen();
  46.  
  47. #ifndef PROTO
  48. extern long SetFunction();
  49. #endif
  50. /*
  51.  *  We trap these routines via SetFunction in order to make vSscreen work.
  52.  */
  53. #ifndef PROTO
  54. extern void MoveSprite();
  55. extern void LoadView();
  56. extern void AutoRequest();
  57. extern void BuildSysRequest();
  58. extern void CloseScreen();
  59. #endif
  60. extern long LVOMoveSprite;
  61. extern long LVOLoadView;
  62. extern long LVOAutoRequest;
  63. extern long LVOBuildSysRequest;
  64. --MORE--(10%)extern long LVOCloseScreen;
  65. /*
  66.  *  CreateNonSigPort()
  67.  *
  68.  *  Creates a message port with signal type PA_IGNORE.  Based on
  69.  *  CreatePort() from the exec support functions documented in the RKM.
  70.  */
  71. struct MsgPort *CreateNonSigPort(name,pri)
  72. char *name;
  73. BYTE pri;
  74. {
  75.    struct MsgPort *thePort;
  76.    
  77.    thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
  78.                                          MEMF_PUBLIC | MEMF_CLEAR);
  79.    if (thePort)
  80.    {
  81.       thePort->mp_Node.ln_Name = name;
  82.       thePort->mp_Node.ln_Pri  = pri;
  83.       thePort->mp_Node.ln_Type = NT_MSGPORT;
  84. --MORE--(11%)      
  85.       thePort->mp_Flags = PA_IGNORE;
  86.       thePort->mp_SigBit = 0;
  87.       thePort->mp_SigTask = NULL;
  88.       
  89.       if (name)
  90.          AddPort(thePort);
  91.         else
  92.          NewList(&(thePort->mp_MsgList));
  93.    }
  94.    return(thePort);
  95. }
  96. /*
  97.  *  DeleteNonSigPort()
  98.  *
  99.  *  Deletes a message port with signal type PA_IGNORE.  Based on
  100.  *  DeletePort() from the exec support functions documented in the RKM
  101.  */
  102. void DeleteNonSigPort(thePort)
  103. struct MsgPort *thePort;
  104. --MORE--(12%){
  105.    if (thePort->mp_Node.ln_Name) RemPort(thePort);
  106.    thePort->mp_Node.ln_Type = 0xFF;
  107.    thePort->mp_MsgList.lh_Head = (struct Node *) -1;
  108.    FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
  109. }
  110. /*
  111.  *  DoExit()
  112.  *
  113.  *  Exit with error status.  Print a message with up to three parameters
  114.  *  and then clean up everything (restore the screen if it is enlarged,
  115.  *  unload the handler if it is loaded, close the Input.Device and free
  116.  *  its IO blocks and ports, and close any open libraries).  Return the
  117.  *  error status.
  118.  */
  119. void DoExit(s,x1,x2,x3)
  120. char *s, *x1,*x2,*x3;
  121. {
  122.    int status = OK_EXIT;
  123. --MORE--(13%)   if (s)
  124.    {
  125.       printf(s,x1,x2,x3);
  126.       printf("\n");
  127.       status = ERROR_EXIT;
  128.    }
  129.    if (Enlarged)        RestoreScreen();
  130.    if (NamedPort)       DeleteNonSigPort(NamedPort);
  131.    if (Segment)         UnLoadSeg(Segment);
  132.    if (InputDevice)     CloseDevice(InputBlock);
  133.    if (InputBlock)      DeleteStdIO(InputBlock);
  134.    if (InputPort)       DeletePort(InputPort);
  135.    if (IntuitionBase)   CloseLibrary(IntuitionBase);
  136.    if (GfxBase)         CloseLibrary(GfxBase);
  137.    if (LayersBase)      CloseLibrary(LayersBase);
  138.    exit(status);
  139. }
  140. /*
  141.  *  CheckLibOpen()
  142.  *
  143.  *  Call OpenLibrary() for the specified library, and check that the 
  144. --MORE--(15%) *  open succeeded.
  145.  */
  146. void CheckLibOpen(lib,name,rev)
  147. APTR *lib;
  148. char *name;
  149. int rev;
  150. {
  151.    #ifndef PROTO
  152.    extern APTR OpenLibrary();
  153.    #endif
  154.    
  155.    if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
  156.       DoExit("Can't open '%s'",name);
  157. }
  158. /*
  159.  *  GetInt()
  160.  *
  161.  *  Read the first integer from the given string variable (used to parse
  162.  *  the command-line arguments).  If no integer can be read, exit and
  163.  *  show the usage string.
  164. --MORE--(16%) */
  165. static long GetInt(s)
  166. char *s;
  167. {
  168.    long i;
  169.    if (sscanf(s,"%ld",&i) != 1) DoExit("Usage:  %s",USAGE);
  170.    return(i);
  171. }
  172. /*
  173.  *  ParseArguments()
  174.  *
  175.  *  Parse the command-line arguments.  If there are too many or too few
  176.  *  arguments, exit with an error message, otherwise get the width and height
  177.  *  agruments.  If there was a screen name specified, record that.
  178.  *  Find the specified screen.
  179.  */
  180. static void ParseArguments(argc,argv)
  181. int argc;
  182. --MORE--(17%)char *argv[];
  183. {
  184.    char *ScreenName = NULL;
  185.    if (argc < 3) DoExit("Width and Height are required\nUsage:  %s",USAGE);
  186.    if (argc > 4) DoExit("Too many arguments");
  187.    ScreenWidth  = GetInt(argv[1]);
  188.    ScreenHeight = GetInt(argv[2]);
  189.    if (ScreenWidth <= 0 || ScreenHeight <= 0)
  190.       DoExit("Screen height and width must be positive");
  191.    if (ScreenWidth > 1024 || ScreenHeight > 1024)
  192.       printf("Warning:  sizes greater than 1024 may cause Blitter problems\n");
  193.    if (argc > 3 && argv[3] && argv[3][0] != '\0') ScreenName = argv[3];
  194.    VScreen = FindScreen(ScreenName);
  195. }
  196. /*
  197.  *  LoadHandler()
  198.  *
  199.  *  Try to LoadSeg the handler from the current directory, and if it is not
  200.  *  found, try the L: directory.  If neither can be loaded, exit with a 
  201.  *  message.  Once the handler is loaded, call its Setup routine passing it
  202. --MORE--(19%) *  our version number.  The handler will check the versions for compatability,
  203.  *  and return NULL for version mismatch, or a pointer to its data structure
  204.  *  with pointers to the variables that vScreen will initialize for it.
  205.  *  LoadHandler() sets the pointer to the handlers SegList, and sets the
  206.  *  loader version number
  207.  */
  208. static void LoadHandler()
  209. {
  210.    struct vScreenInfo *(*Setup)();
  211.    if ((Segment = LoadSeg(HANDLER)) == NULL)
  212.       if ((Segment = LoadSeg(handler)) == NULL)
  213.          DoExit("Can't Load '%s'",handler);
  214.    Setup = (struct vScreenInfo *(*)()) ((Segment << 2) + 4);
  215.    
  216.    vScreenData   = (*Setup)(LOADVERS);
  217.    if (vScreenData)
  218.    {
  219.       if (var(MajVers) > 1) DoExit("version mismatch with '%s'",HANDLER);
  220.    } else {
  221.       DoExit("'%s' reports a version mismatch",HANDLER);
  222.    }
  223. --MORE--(21%)
  224.    var(Segment)  = Segment;
  225.    var(LoadVers) = LOADVERS;
  226. }
  227. /*
  228.  *  TellInputDevice()
  229.  *
  230.  *  Create a port and I/O block, then open the input device.  Set up the
  231.  *  I/O block to add or remove the input handler, and send the request
  232.  *  to the input device.  Finally, close the device and delete the
  233.  *  I/O block and port.
  234.  */
  235.  
  236. void TellInputDevice(function)
  237. int function;
  238. {
  239.    long status;
  240.    if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
  241.    if ((InputBlock = CreateStdIO(InputPort)) == NULL)
  242.       DoExit("Can't Create Standard IO Block");
  243. --MORE--(22%)   InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
  244.    if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
  245.    
  246.    InputBlock->io_Command = (long) function;
  247.    InputBlock->io_Data    = (APTR) vScreenData->HandlerInfo;
  248.    if (status = DoIO(InputBlock)) DoExit("Error from DoIO:  %ld",status);
  249.    CloseDevice(InputBlock); InputDevice = FALSE;
  250.    DeleteStdIO(InputBlock); InputBlock = NULL;
  251.    DeletePort(InputPort);   InputPort = NULL;
  252. }
  253. /*
  254.  *  SetVectors()
  255.  *
  256.  *  Call SetFunction() to replace the library vectores for the routines that
  257.  *  we need to trap.  Use the routines that the handler has supplied (they
  258.  *  were passed to us in the vScreenData structure).  Save the old vectors
  259.  *  in the vScreenData strucutre so we can replace them later.  Set the 
  260.  *  jump addresses so that the stub routines can call the old vectors.
  261.  *  I Know this is a kludge, and is a form of self-modifying code, but I
  262.  *  can't figure out a better method.  The JSR (Ax) is only good when there
  263. --MORE--(24%) *  is a free A register, which is not always the case.
  264.  */
  265. void SetVectors()
  266. {
  267.    var(OldCloseScreen) =
  268.        SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
  269.    var(CloseScreenJmpTarget)[-1] = (long) var(OldCloseScreen);
  270.    var(OldBuildSysRequest) =
  271.        SetFunction(IntuitionBase,&LVOBuildSysRequest,var(aBuildSysRequest));
  272.    var(BuildSysRequestJmpTarget)[-1] = (long) var(OldBuildSysRequest);
  273.    var(OldAutoRequest) =
  274.       SetFunction(IntuitionBase,&LVOAutoRequest,var(aAutoRequest));
  275.    var(AutoRequestJmpTarget)[-1] = (long) var(OldAutoRequest);
  276.    var(OldLoadView) = SetFunction(GfxBase,&LVOLoadView,var(aLoadView));
  277.    var(LoadViewJmpTarget)[-1] = (long) var(OldLoadView);
  278.    var(OldMoveSprite) = SetFunction(GfxBase,&LVOMoveSprite,var(aMoveSprite));
  279.    var(MoveSpriteJmpTarget)[-1] = (long) var(OldMoveSprite);
  280. }
  281. --MORE--(26%)
  282. /*
  283.  *  UnSetVectors()
  284.  *
  285.  *  Put back the old jump vectors for the routines that we replaced.
  286.  *  Make sure that no one else has replced them behind our backs, however.
  287.  *  If they are not the same way we left them, return an error status.
  288.  */
  289. int UnSetVectors()
  290. {
  291.    long NewCloseScreen,NewBuildSysRequest,NewAutoRequest,
  292.         NewLoadView,NewMoveSprite;
  293.    int status = TRUE;
  294.    NewCloseScreen =
  295.       SetFunction(IntuitionBase,&LVOCloseScreen,var(OldCloseScreen));
  296.    NewBuildSysRequest =
  297.       SetFunction(IntuitionBase,&LVOBuildSysRequest,var(OldBuildSysRequest));
  298.    NewAutoRequest =
  299.       SetFunction(IntuitionBase,&LVOAutoRequest,var(OldAutoRequest));
  300.    NewLoadView   = SetFunction(GfxBase,&LVOLoadView,var(OldLoadView));
  301. --MORE--(28%)   NewMoveSprite = SetFunction(GfxBase,&LVOMoveSprite,var(OldMoveSprite));
  302.    if (NewCloseScreen     != (long) var(aCloseScreen) ||
  303.        NewBuildSysRequest != (long) var(aBuildSysRequest) ||
  304.        NewAutoRequest     != (long) var(aAutoRequest) ||
  305.        NewLoadView        != (long) var(aLoadView) ||
  306.        NewMoveSprite      != (long) var(aMoveSprite))
  307.    {
  308.       SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
  309.       SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
  310.       SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
  311.       SetFunction(GfxBase,&LVOLoadView,NewLoadView);
  312.       SetFunction(GfxBase,&LVOMoveSprite,NewMoveSprite);
  313.       status = FALSE;
  314.    }
  315.    return(status);
  316. }
  317. /*
  318.  *  main()
  319.  *
  320.  *  Look for the vScreen port.
  321. --MORE--(30%) *  If one does not exist then vScreen is not currently active, so
  322.  *    open the intuition and graphics libraries.
  323.  *    Parse the command-line arguments to get the width, height, and screen.
  324.  *    Load the handler code, and check its version.
  325.  *    Create the named port used to store information about the handler.
  326.  *    Setup some of the variables needed by the handler, and save a pointer
  327.  *      to the handler data in the named port.
  328.  *    Try to enlarge the size of the screen bitmap, and set more variables.
  329.  *    Add the input handler into the input chain.
  330.  *    SetFunction the neede vectors.  At this point vScreen is active.
  331.  *    Print a message that reports the version numbers.
  332.  *  Otherwise (the port already exists, so vScreen already is active)
  333.  *    Get the pointer to the vScreenData structure from the port.
  334.  *    If they user had supplied arguments, tell him vScreen already is running.
  335.  *    Try to unset the routines we replaced earlier.
  336.  *    If the vectors we removed successfully then
  337.  *      Remove the input handler.
  338.  *      Restore the screen to its original size.
  339.  *      Delete the (no-longer-needed) named port.
  340.  *      Unload the handler code.
  341.  *      Tell the user that the code is removed.
  342.  *      Close the libraries (note that these remained open between calls 
  343.  *        to vScreen, while the handler was active).
  344. --MORE--(33%) *    Otherwise (we could not replce the function vectors)
  345.  *      Report the problem, and leave the handler running.
  346.  */
  347. void main(argc,argv)
  348. int argc;
  349. char *argv[];
  350. {
  351.    NamedPort = FindPort(PORTNAME);
  352.    if (NamedPort == NULL)
  353.    {
  354.       CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
  355.       CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
  356.       ParseArguments(argc,argv);
  357.       LoadHandler();
  358.       if ((NamedPort = CreateNonSigPort(var(PortName),0L)) == NULL)
  359.          DoExit("Can't Create Message Port '%s'",var(PortName));
  360.       SetVariables(NamedPort);
  361.       Enlarged = EnlargeScreen();
  362.       TellInputDevice(IND_ADDHANDLER);
  363.       SetVectors();
  364. --MORE--(35%)
  365.       printf("%s v%d.%d.%d Installed\n",program,
  366.          var(MajVers),var(MinVers),var(LoadVers));
  367.    } else {
  368.       GetVariables(NamedPort);
  369.       if (argc > 1)
  370.       {
  371.          printf("%s already active on screen '%s'\n",program,VScreen->Title);
  372.       } else {
  373.          if (UnSetVectors())
  374.          {
  375.             TellInputDevice(IND_REMHANDLER);
  376.             RestoreScreen();
  377.             DeleteNonSigPort(NamedPort);
  378.             UnLoadSeg(var(Segment));
  379.             printf("%s Removed\n",program);
  380.             CloseLibrary(IntuitionBase);
  381.             CloseLibrary(GfxBase);
  382.          } else {
  383.             printf("SetFunction vectors have been changed!\n");
  384.             printf("%s Not Removed\n",program);
  385.          }
  386.       }
  387. --MORE--(36%)   }
  388. }
  389.