/* * ZOOM-DAEMON A program that implements Zoom gadgets for all Intuition * windows that are opened while it is running. * * Copyright 1989 by Davide P. Cervone. * You may use this code, provided this copyright notice is kept intact. */ #include "Zoom-Main.h" #include "Zoom-Daemon.h" struct IntuitionBase *IntuitionBase = NULL; extern struct SysBase *SysBase; static char *program = PROGRAM; static char *copyright = COPYRIGHT; static char *handler = HANDLERCODE; /* The name of the handler file */ #define HANDLER &(handler[2]) /* Handler without the L: */ static struct Zoom_HandlerInfo *Zoom_HandlerData; /* data shared with handler */ static long Segment; /* The loaded handler segment */ static struct ExtGadget *FirstZoom; /* The list of zoom gadgets */ static struct MsgPort *InputPort; /* To talk to Input.Device */ static struct IOStdReq *InputBlock; /* IO block for Input.Device */ static int InputDevice; /* Is Input.Device open? */ static int VectorsSet; /* TRUE after SetFunction */ /* * DoExit() * * General purpose error-exit routine. Print an error message if one was * supplied (it can have up to three parameters), and then clean up any * memory, libraries, etc. that need to be handled before exiting. */ static void DoExit(s,x1,x2,x3) char *s, *x1, *x2, *x3; { long status = EXIT_OK; if (s != NULL) { printf(s,x1,x2,x3); printf("\n"); status = EXIT_ERROR; } if (VectorsSet) UnSetVectors(); if (InputDevice) CloseDevice(InputBlock); if (InputBlock) DeleteStdIO(InputBlock); if (InputPort) DeletePort(InputPort); if (Segment) UnLoadSeg(Segment); if (IntuitionBase) CloseLibrary(IntuitionBase); exit(status); } /* * CheckLibOpen() * * Call OpenLibrary() for the specified library, and check that the * open succeeded. */ static void CheckLibOpen(lib,name,rev) APTR *lib; char *name; int rev; { extern APTR OpenLibrary(); if ((*lib = OpenLibrary(name,(LONG)rev)) == NULL) DoExit("Can't open %s",name); } /* * 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 an * error message. Once the handler is loaded, call the Setup routine * in the handler code and pass the loader version number. The handler will * check the version for compatibility and returns NULL if there is a * mismatch, or a pointer to the shared data if everything is OK. * Check the handler version number, and then store the loader version * and the segment list pointer for use in unloading the handler later. * The MsgPort is the first item in the Zoom_Handler structure. It is used * to link the information into the system port list, where we can find it * later. */ void LoadHandler(thePort) struct MsgPort **thePort; { struct Zoom_HandlerInfo *(*Setup)(); if ((Segment = LoadSeg(HANDLER)) == NULL) if ((Segment = LoadSeg(handler)) == NULL) DoExit("Can't load %s",handler); Setup = (struct Zoom_HandlerInfo *(*)()) ((Segment << 2) + 4); Zoom_HandlerData = (*Setup)(LOADVERS); if (Zoom_HandlerData) { if (var(MajVers) < MINHMAJVERS || (var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS)) DoExit("Version mismatch with %s",HANDLER); *thePort = &(Zoom_HandlerData->Zoom_Port); } else { DoExit("%s reports a version mismatch",HANDLER); } var(Segment) = Segment; } /* * 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; extern struct MsgPort *CreatePort(); extern struct IOStdReq *CreateStdIO(); if ((InputPort = CreatePort(0,0)) == NULL) DoExit("Can't Create Port"); if ((InputBlock = CreateStdIO(InputPort)) == NULL) DoExit("Can't Create Standard IO Block"); 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) var(Zoom_Interrupt); if (status = DoIO(InputBlock)) DoExit("Error from DoIO: %ld",status); CloseDevice(InputBlock); InputDevice = FALSE; DeleteStdIO(InputBlock); InputBlock = NULL; DeletePort(InputPort); InputPort = NULL; } /* * SetVectors() * * Set the Intuition library vectors for the routines specified by the * handler. Save the old routine pointers for later replacement. */ void SetVectors() { VAR(OldOpenWindow) = SetFunction(IntuitionBase,&LVOOpenWindow,var(aOpenWindow)); VAR(OldCloseWindow) = SetFunction(IntuitionBase,&LVOCloseWindow,var(aCloseWindow)); VAR(OldAddGadget) = SetFunction(IntuitionBase,&LVOAddGadget,var(aAddGadget)); VAR(OldAddGList) = SetFunction(IntuitionBase,&LVOAddGList,var(aAddGList)); VectorsSet = TRUE; } /* * UnSetVectors() * * Replace the old Intuition library vectors, but make sure that no one * else has changed them behind our back. If they are not the same as * what we set them to originally, then put back the ones that we found, * and return an error status. */ int UnSetVectors() { long NewOpenWindow; long NewCloseWindow; long NewAddGadget; long NewAddGList; int status = TRUE; Forbid(); NewOpenWindow = SetFunction(IntuitionBase,&LVOOpenWindow,VAR(OldOpenWindow)); NewCloseWindow = SetFunction(IntuitionBase,&LVOCloseWindow,VAR(OldCloseWindow)); NewAddGadget = SetFunction(IntuitionBase,&LVOAddGadget,VAR(OldAddGadget)); NewAddGList = SetFunction(IntuitionBase,&LVOAddGList,VAR(OldAddGList)); if (NewOpenWindow != (long) var(aOpenWindow) || NewCloseWindow != (long) var(aCloseWindow) || NewAddGadget != (long) var(aAddGadget) || NewAddGList != (long) var(aAddGList)) { SetFunction(IntuitionBase,&LVOOpenWindow,NewOpenWindow); SetFunction(IntuitionBase,&LVOCloseWindow,NewCloseWindow); SetFunction(IntuitionBase,&LVOAddGadget,NewAddGadget); SetFunction(IntuitionBase,&LVOAddGList,NewAddGList); status = FALSE; } Permit(); return(status); } /* * SetVariables() * * The Zoom_HandlerData structure is used to allow the loading program to * set up variables needed by the handler (like Intuitionbase, etc.). This * keeps the handler code to a minimum. The loader retains pointers to the * linked lists, in case it needs to free memory on behalf of the handler. */ void SetVariables(thePort) struct MsgPort *thePort; { VAR(IntuitionBase) = IntuitionBase; VAR(SysBase) = SysBase; VAR(FirstZoom) = NULL; } /* * GetVariables() * * Look up the values stored in the Zoom_HandlerData structure. The * Intuition library already was opened, and we will need to close it. * The data in the linked lists may need to be freed. */ void GetVariables(thePort) struct MsgPort *thePort; { Zoom_HandlerData = (struct Zoom_HandlerInfo *)thePort; IntuitionBase = VAR(IntuitionBase); FirstZoom = VAR(FirstZoom); } /* * SetupWindows() * * Looks through the Intuition screen and windows lists and * calls the Handler's SetupWindow routine to add the imagery to * each pre-existing window. * * All of this is done in Forbid() mode so that the list won't change * while we're looking. */ static void SetupWindows() { struct Screen *theScreen; struct Window *theWindow; if (var(SetupWindow)) { Forbid(); theScreen = IntuitionBase->FirstScreen; while (theScreen) { theWindow = theScreen->FirstWindow; while (theWindow) { VAR(SetupWindow)(theWindow); theWindow = theWindow->NextWindow; } theScreen = theScreen->NextScreen; } Permit(); } } /* * FreeAllZoomGadgets(); * * Goes through the linked list of zoom gadgets and removes each * from its associated window, refreshes the window, and frees * the memory associated with the zoom gadget. */ void FreeAllZoomGadgets() { struct ExtGadget *theGadget; while (FirstZoom) { theGadget = FirstZoom; FirstZoom = theGadget->Next; RemoveGadget(theGadget->Window,&(theGadget->Gadget)); RefreshWindowFrame(theGadget->Window); FreeMem(theGadget,EXTGADGETSIZE); } FirstZoom = NULL; } /* * Main() * * Look for the Zoom-Daemon port. * If the port does not exist, then Zoom-Daemon is not active, so: * Open Intuition. * Load the handler code and check its version. * Add the port (supplied by the handler) into the system list so we * can find it later. * Set the variables needed by the handler. * Set the Intuition Library vectors for the handler routines * Add the input handler into the Input Device chain * Retro-fit existing windows to include the Zoom Gadgets * Notify the user that all is ready. * else (the port already exists, so Zoom-Daemon alreay is active) * Get the pointer to the Zoom_HandlerData structure from the port, * and get any variables we need from the structure. * Check that the loader versions are compatible. * Remove the input handler from the Input Device chain * Try to remove the SetFunction calls. * If successfull, then * Remove the port from the system list. * Cleanup and windows that are still using the Zoom Gadgets * Unload the handler segment list. * Notify the user that Zoom-Daemon is deactivated. * Close Intuition. * else (we could not replace the functions) * Put back the input handler * Inform the user that Zoom-Daemon can not be removed */ void main() { struct MsgPort *NamedPort; NamedPort = FindPort(PORTNAME); if (NamedPort == NULL) { CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV); LoadHandler(&NamedPort); AddPort(NamedPort); SetVariables(NamedPort); SetVectors(NamedPort); TellInputDevice(IND_ADDHANDLER); SetupWindows(); printf("%s v%d.%d.%d Installed\n",program, var(MajVers),var(MinVers),LOADVERS); } else { GetVariables(NamedPort); if (var(MinLoadVers) > LOADVERS || var(MajVers) < MINHMAJVERS || (var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS)) { printf("Loader version mismatch\n"); printf("%s not removed\n",program); } else { TellInputDevice(IND_REMHANDLER); if (UnSetVectors(NamedPort)) { RemPort(NamedPort); FreeAllZoomGadgets(); UnLoadSeg(var(Segment)); printf("%s removed\n",program); CloseLibrary(IntuitionBase); } else { TellInputDevice(IND_ADDHANDLER); printf("SetFunction vectors have been changed!\n"); printf("Cannot remove %s\n",program); } } } }