home *** CD-ROM | disk | FTP | other *** search
- /*
- * VSCREEN.C Creates virtual screens that can be larger than
- * the actual display area of your monitor. The virtual
- * screen scrolls when the mouse moves off the edge of
- * the display.
- *
- * Copyright 1988 by Davide P. Cervone, all rights reserved.
- *
- --MORE--(4%) * You may may distibute this code as is, for non-commercial
- * purposes, provided that this notice remains intact and the
- * documentation file is distributed with it.
- *
- * You may not modify this code or incorporate it into your
- * own programs without the permission of the author.
- */
- /*
- * WARNING: This code uses and even modifies the INTUITIONPRIVATE
- * area of the IntuitionBase structure. Use it at your own risk. It is
- * likely to break under a future release of Intuition.
- */
- #include "vScreen.h"
- static char *program = "vScreen"; /* the program name */
- static char *author = COPYRIGHT; /* the copyright notice */
- #define LOADVERS 1 /* this program's version */
- static char *handler = "L:vScreen-Handler"; /* the name of the handler */
- #define HANDLER &(handler[2]) /* same but in the current dir */
- --MORE--(6%)
- extern struct LayersBase *LayersBase; /* the Layers library */
-
- struct vScreenInfo *vScreenData; /* data needed by the handler */
- struct Screen *VScreen = NULL; /* the virtual screen */
- static long Segment = NULL; /* the loaded handler */
- SHORT ScreenWidth,ScreenHeight; /* the new screen sizes */
- static struct MsgPort *NamedPort = NULL; /* used to find the handler later */static struct MsgPort *InputPort = NULL; /* to talk to Input.Device */
- static struct IOStdReq *InputBlock = NULL; /* IO block for Input.Device */
- static short InputDevice = FALSE; /* is Input.Device open? */
- static int Enlarged = FALSE; /* is screen changed? */
- /*
- * These routines are in vScreenSetup.c
- */
- extern struct Screen *FindScreen();
- extern void SetVariables();
- extern void GetVariables();
- extern int EnlargeScreen();
- --MORE--(9%)extern void RestoreScreen();
-
- #ifndef PROTO
- extern long SetFunction();
- #endif
- /*
- * We trap these routines via SetFunction in order to make vSscreen work.
- */
- #ifndef PROTO
- extern void MoveSprite();
- extern void LoadView();
- extern void AutoRequest();
- extern void BuildSysRequest();
- extern void CloseScreen();
- #endif
- extern long LVOMoveSprite;
- extern long LVOLoadView;
- extern long LVOAutoRequest;
- extern long LVOBuildSysRequest;
- --MORE--(10%)extern long LVOCloseScreen;
- /*
- * CreateNonSigPort()
- *
- * Creates a message port with signal type PA_IGNORE. Based on
- * CreatePort() from the exec support functions documented in the RKM.
- */
- struct MsgPort *CreateNonSigPort(name,pri)
- char *name;
- BYTE pri;
- {
- struct MsgPort *thePort;
-
- thePort = (struct MsgPort *)AllocMem((ULONG)sizeof(struct MsgPort),
- MEMF_PUBLIC | MEMF_CLEAR);
- if (thePort)
- {
- thePort->mp_Node.ln_Name = name;
- thePort->mp_Node.ln_Pri = pri;
- thePort->mp_Node.ln_Type = NT_MSGPORT;
- --MORE--(11%)
- thePort->mp_Flags = PA_IGNORE;
- thePort->mp_SigBit = 0;
- thePort->mp_SigTask = NULL;
-
- if (name)
- AddPort(thePort);
- else
- NewList(&(thePort->mp_MsgList));
- }
- return(thePort);
- }
- /*
- * DeleteNonSigPort()
- *
- * Deletes a message port with signal type PA_IGNORE. Based on
- * DeletePort() from the exec support functions documented in the RKM
- */
- void DeleteNonSigPort(thePort)
- struct MsgPort *thePort;
- --MORE--(12%){
- if (thePort->mp_Node.ln_Name) RemPort(thePort);
- thePort->mp_Node.ln_Type = 0xFF;
- thePort->mp_MsgList.lh_Head = (struct Node *) -1;
- FreeMem(thePort,(ULONG)sizeof(struct MsgPort));
- }
- /*
- * DoExit()
- *
- * Exit with error status. Print a message with up to three parameters
- * and then clean up everything (restore the screen if it is enlarged,
- * unload the handler if it is loaded, close the Input.Device and free
- * its IO blocks and ports, and close any open libraries). Return the
- * error status.
- */
- void DoExit(s,x1,x2,x3)
- char *s, *x1,*x2,*x3;
- {
- int status = OK_EXIT;
- --MORE--(13%) if (s)
- {
- printf(s,x1,x2,x3);
- printf("\n");
- status = ERROR_EXIT;
- }
- if (Enlarged) RestoreScreen();
- if (NamedPort) DeleteNonSigPort(NamedPort);
- if (Segment) UnLoadSeg(Segment);
- if (InputDevice) CloseDevice(InputBlock);
- if (InputBlock) DeleteStdIO(InputBlock);
- if (InputPort) DeletePort(InputPort);
- if (IntuitionBase) CloseLibrary(IntuitionBase);
- if (GfxBase) CloseLibrary(GfxBase);
- if (LayersBase) CloseLibrary(LayersBase);
- exit(status);
- }
- /*
- * CheckLibOpen()
- *
- * Call OpenLibrary() for the specified library, and check that the
- --MORE--(15%) * open succeeded.
- */
- void CheckLibOpen(lib,name,rev)
- APTR *lib;
- char *name;
- int rev;
- {
- #ifndef PROTO
- extern APTR OpenLibrary();
- #endif
-
- if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
- DoExit("Can't open '%s'",name);
- }
- /*
- * GetInt()
- *
- * Read the first integer from the given string variable (used to parse
- * the command-line arguments). If no integer can be read, exit and
- * show the usage string.
- --MORE--(16%) */
- static long GetInt(s)
- char *s;
- {
- long i;
- if (sscanf(s,"%ld",&i) != 1) DoExit("Usage: %s",USAGE);
- return(i);
- }
- /*
- * ParseArguments()
- *
- * Parse the command-line arguments. If there are too many or too few
- * arguments, exit with an error message, otherwise get the width and height
- * agruments. If there was a screen name specified, record that.
- * Find the specified screen.
- */
- static void ParseArguments(argc,argv)
- int argc;
- --MORE--(17%)char *argv[];
- {
- char *ScreenName = NULL;
- if (argc < 3) DoExit("Width and Height are required\nUsage: %s",USAGE);
- if (argc > 4) DoExit("Too many arguments");
- ScreenWidth = GetInt(argv[1]);
- ScreenHeight = GetInt(argv[2]);
- if (ScreenWidth <= 0 || ScreenHeight <= 0)
- DoExit("Screen height and width must be positive");
- if (ScreenWidth > 1024 || ScreenHeight > 1024)
- printf("Warning: sizes greater than 1024 may cause Blitter problems\n");
- if (argc > 3 && argv[3] && argv[3][0] != '\0') ScreenName = argv[3];
- VScreen = FindScreen(ScreenName);
- }
- /*
- * LoadHandler()
- *
- * Try to LoadSeg the handler from the current directory, and if it is not
- * found, try the L: directory. If neither can be loaded, exit with a
- * message. Once the handler is loaded, call its Setup routine passing it
- --MORE--(19%) * our version number. The handler will check the versions for compatability,
- * and return NULL for version mismatch, or a pointer to its data structure
- * with pointers to the variables that vScreen will initialize for it.
- * LoadHandler() sets the pointer to the handlers SegList, and sets the
- * loader version number
- */
- static void LoadHandler()
- {
- struct vScreenInfo *(*Setup)();
- if ((Segment = LoadSeg(HANDLER)) == NULL)
- if ((Segment = LoadSeg(handler)) == NULL)
- DoExit("Can't Load '%s'",handler);
- Setup = (struct vScreenInfo *(*)()) ((Segment << 2) + 4);
-
- vScreenData = (*Setup)(LOADVERS);
- if (vScreenData)
- {
- if (var(MajVers) > 1) DoExit("version mismatch with '%s'",HANDLER);
- } else {
- DoExit("'%s' reports a version mismatch",HANDLER);
- }
- --MORE--(21%)
- var(Segment) = Segment;
- var(LoadVers) = LOADVERS;
- }
- /*
- * TellInputDevice()
- *
- * Create a port and I/O block, then open the input device. Set up the
- * I/O block to add or remove the input handler, and send the request
- * to the input device. Finally, close the device and delete the
- * I/O block and port.
- */
-
- void TellInputDevice(function)
- int function;
- {
- long status;
- if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port");
- if ((InputBlock = CreateStdIO(InputPort)) == NULL)
- DoExit("Can't Create Standard IO Block");
- --MORE--(22%) InputDevice = (OpenDevice("input.device",0,InputBlock,0) == 0);
- if (InputDevice == FALSE) DoExit("Can't Open 'input.device'");
-
- InputBlock->io_Command = (long) function;
- InputBlock->io_Data = (APTR) vScreenData->HandlerInfo;
- if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status);
- CloseDevice(InputBlock); InputDevice = FALSE;
- DeleteStdIO(InputBlock); InputBlock = NULL;
- DeletePort(InputPort); InputPort = NULL;
- }
- /*
- * SetVectors()
- *
- * Call SetFunction() to replace the library vectores for the routines that
- * we need to trap. Use the routines that the handler has supplied (they
- * were passed to us in the vScreenData structure). Save the old vectors
- * in the vScreenData strucutre so we can replace them later. Set the
- * jump addresses so that the stub routines can call the old vectors.
- * I Know this is a kludge, and is a form of self-modifying code, but I
- * can't figure out a better method. The JSR (Ax) is only good when there
- --MORE--(24%) * is a free A register, which is not always the case.
- */
- void SetVectors()
- {
- var(OldCloseScreen) =
- SetFunction(IntuitionBase,&LVOCloseScreen,var(aCloseScreen));
- var(CloseScreenJmpTarget)[-1] = (long) var(OldCloseScreen);
- var(OldBuildSysRequest) =
- SetFunction(IntuitionBase,&LVOBuildSysRequest,var(aBuildSysRequest));
- var(BuildSysRequestJmpTarget)[-1] = (long) var(OldBuildSysRequest);
- var(OldAutoRequest) =
- SetFunction(IntuitionBase,&LVOAutoRequest,var(aAutoRequest));
- var(AutoRequestJmpTarget)[-1] = (long) var(OldAutoRequest);
- var(OldLoadView) = SetFunction(GfxBase,&LVOLoadView,var(aLoadView));
- var(LoadViewJmpTarget)[-1] = (long) var(OldLoadView);
- var(OldMoveSprite) = SetFunction(GfxBase,&LVOMoveSprite,var(aMoveSprite));
- var(MoveSpriteJmpTarget)[-1] = (long) var(OldMoveSprite);
- }
- --MORE--(26%)
- /*
- * UnSetVectors()
- *
- * Put back the old jump vectors for the routines that we replaced.
- * Make sure that no one else has replced them behind our backs, however.
- * If they are not the same way we left them, return an error status.
- */
- int UnSetVectors()
- {
- long NewCloseScreen,NewBuildSysRequest,NewAutoRequest,
- NewLoadView,NewMoveSprite;
- int status = TRUE;
- NewCloseScreen =
- SetFunction(IntuitionBase,&LVOCloseScreen,var(OldCloseScreen));
- NewBuildSysRequest =
- SetFunction(IntuitionBase,&LVOBuildSysRequest,var(OldBuildSysRequest));
- NewAutoRequest =
- SetFunction(IntuitionBase,&LVOAutoRequest,var(OldAutoRequest));
- NewLoadView = SetFunction(GfxBase,&LVOLoadView,var(OldLoadView));
- --MORE--(28%) NewMoveSprite = SetFunction(GfxBase,&LVOMoveSprite,var(OldMoveSprite));
- if (NewCloseScreen != (long) var(aCloseScreen) ||
- NewBuildSysRequest != (long) var(aBuildSysRequest) ||
- NewAutoRequest != (long) var(aAutoRequest) ||
- NewLoadView != (long) var(aLoadView) ||
- NewMoveSprite != (long) var(aMoveSprite))
- {
- SetFunction(IntuitionBase,&LVOCloseScreen,NewCloseScreen);
- SetFunction(IntuitionBase,&LVOBuildSysRequest,NewBuildSysRequest);
- SetFunction(IntuitionBase,&LVOAutoRequest,NewAutoRequest);
- SetFunction(GfxBase,&LVOLoadView,NewLoadView);
- SetFunction(GfxBase,&LVOMoveSprite,NewMoveSprite);
- status = FALSE;
- }
- return(status);
- }
- /*
- * main()
- *
- * Look for the vScreen port.
- --MORE--(30%) * If one does not exist then vScreen is not currently active, so
- * open the intuition and graphics libraries.
- * Parse the command-line arguments to get the width, height, and screen.
- * Load the handler code, and check its version.
- * Create the named port used to store information about the handler.
- * Setup some of the variables needed by the handler, and save a pointer
- * to the handler data in the named port.
- * Try to enlarge the size of the screen bitmap, and set more variables.
- * Add the input handler into the input chain.
- * SetFunction the neede vectors. At this point vScreen is active.
- * Print a message that reports the version numbers.
- * Otherwise (the port already exists, so vScreen already is active)
- * Get the pointer to the vScreenData structure from the port.
- * If they user had supplied arguments, tell him vScreen already is running.
- * Try to unset the routines we replaced earlier.
- * If the vectors we removed successfully then
- * Remove the input handler.
- * Restore the screen to its original size.
- * Delete the (no-longer-needed) named port.
- * Unload the handler code.
- * Tell the user that the code is removed.
- * Close the libraries (note that these remained open between calls
- * to vScreen, while the handler was active).
- --MORE--(33%) * Otherwise (we could not replce the function vectors)
- * Report the problem, and leave the handler running.
- */
- void main(argc,argv)
- int argc;
- char *argv[];
- {
- NamedPort = FindPort(PORTNAME);
- if (NamedPort == NULL)
- {
- CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
- CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
- ParseArguments(argc,argv);
- LoadHandler();
- if ((NamedPort = CreateNonSigPort(var(PortName),0L)) == NULL)
- DoExit("Can't Create Message Port '%s'",var(PortName));
- SetVariables(NamedPort);
- Enlarged = EnlargeScreen();
- TellInputDevice(IND_ADDHANDLER);
- SetVectors();
- --MORE--(35%)
- printf("%s v%d.%d.%d Installed\n",program,
- var(MajVers),var(MinVers),var(LoadVers));
- } else {
- GetVariables(NamedPort);
- if (argc > 1)
- {
- printf("%s already active on screen '%s'\n",program,VScreen->Title);
- } else {
- if (UnSetVectors())
- {
- TellInputDevice(IND_REMHANDLER);
- RestoreScreen();
- DeleteNonSigPort(NamedPort);
- UnLoadSeg(var(Segment));
- printf("%s Removed\n",program);
- CloseLibrary(IntuitionBase);
- CloseLibrary(GfxBase);
- } else {
- printf("SetFunction vectors have been changed!\n");
- printf("%s Not Removed\n",program);
- }
- }
- --MORE--(36%) }
- }
-