/* * NL-Daemon A program to force old programs to use NL gadget imagery. * * Copyright 1989 by Davide P. Cervone. * You may use this code, provided this copyright notice is kept intact. */ #include "NL-Main.h" #include "NL-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 NL_HandlerInfo *NL_HandlerData; /* data shared with the handler */ static long Segment; /* the loaded handler segment */ /* * 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 (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 NL_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 NL_HandlerInfo *(*Setup)(); if ((Segment = LoadSeg(HANDLER)) == NULL) if ((Segment = LoadSeg(handler)) == NULL) DoExit("Can't load %s",handler); Setup = (struct NL_HandlerInfo *(*)()) ((Segment << 2) + 4); NL_HandlerData = (*Setup)(LOADVERS); if (NL_HandlerData) { if (var(MajVers) < MINHMAJVERS || (var(MajVers) == MINHMAJVERS && var(MinVers) < MINHMINVERS)) DoExit("Version mismatch with %s",HANDLER); *thePort = &(NL_HandlerData->NL_Port); } else { DoExit("%s reports a version mismatch",HANDLER); } var(Segment) = Segment; } /* * InvertImage() * * Performs a Logical NOT on all the bits in the Image data, and * XORs the second bitplane in the PlaneOnOff field. This makes the * standard Intuition Imagery use color 2 as the background and color * three as the forground (rather than 1 and 0). */ #define IMAGESIZE(i) ((i)->Depth*(((i)->Width+15)>>4)*(i)->Height) static void InvertImage(theImage) struct Image *theImage; { short i; USHORT *theWord; if (theImage) { theWord = theImage->ImageData; for (i=IMAGESIZE(theImage); i; i--,theWord++) *theWord = ~(*theWord); theImage->PlaneOnOff ^= 0x02; } } /* * 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(OldSetMenuStrip) = SetFunction(IntuitionBase,&LVOSetMenuStrip,var(aSetMenuStrip)); VAR(OldOpenScreen) = SetFunction(IntuitionBase,&LVOOpenScreen,var(aOpenScreen)); } /* * 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 NewSetMenuStrip; long NewOpenScreen; int status = TRUE; NewOpenWindow = SetFunction(IntuitionBase,&LVOOpenWindow,VAR(OldOpenWindow)); NewSetMenuStrip = SetFunction(IntuitionBase,&LVOSetMenuStrip,VAR(OldSetMenuStrip)); NewOpenScreen = SetFunction(IntuitionBase,&LVOOpenScreen,VAR(OldOpenScreen)); if (NewOpenWindow != (long) var(aOpenWindow) || NewSetMenuStrip != (long) var(aSetMenuStrip) || NewOpenScreen != (long) var(aOpenScreen)) { SetFunction(IntuitionBase,&LVOOpenWindow,NewOpenWindow); SetFunction(IntuitionBase,&LVOSetMenuStrip,NewSetMenuStrip); SetFunction(IntuitionBase,&LVOOpenScreen,NewOpenScreen); status = FALSE; } return(status); } /* * SetVariables() * * The NL_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,argc) struct MsgPort *thePort; int argc; { VAR(IntuitionBase) = IntuitionBase; VAR(SysBase) = SysBase; if (argc == 1) { Forbid(); InvertImage(IntuitionBase->CheckImage[0]); InvertImage(IntuitionBase->CheckImage[1]); InvertImage(IntuitionBase->AmigaIcon[0]); InvertImage(IntuitionBase->AmigaIcon[1]); Permit(); var(Flags) |= INTUITION_CHANGED; } } /* * GetVariables() * * Look up the values stored in the NL_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; { NL_HandlerData = (struct NL_HandlerInfo *)thePort; IntuitionBase = VAR(IntuitionBase); } /* * 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. If the window has a menu strip, remove * it and then replace it (our SetMenuStrip routine will fix the menu * for us, since it has already be added in via SetFunction). * 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; struct Menu *theMenu; if (var(SetupWindow) || var(SetupScreen)) { Forbid(); theScreen = IntuitionBase->FirstScreen; while (theScreen) { if (var(SetupScreen)) VAR(SetupScreen)(theScreen); if (var(SetupWindow)) { theWindow = theScreen->FirstWindow; while (theWindow) { VAR(SetupWindow)(theWindow); if (theWindow->MenuStrip) { theMenu = theWindow->MenuStrip; ClearMenuStrip(theWindow); SetMenuStrip(theWindow,theMenu); } theWindow = theWindow->NextWindow; } } theScreen = theScreen->NextScreen; } Permit(); } } /* * CheckGadget() * * Checks to see if a gadget's imagery has been changed. If so, it * replaces the imagery with the standard Intuition imagery that we saved * when we set up the NL gadget. */ static int CheckGadget(theGadget,HiResImage,LowResImage) struct Gadget *theGadget; APTR HiResImage,LowResImage; { int status = FALSE; if (theGadget->GadgetRender == HiResImage || theGadget->GadgetRender == LowResImage) { status = TRUE; theGadget->GadgetRender = theGadget->SelectRender; theGadget->LeftEdge = ((LONG)theGadget->UserData) >> 16; theGadget->Width = ((LONG)theGadget->UserData) & 0xFFFF; } return(status); } /* * CheckGadgetList() * * Looks through a list of gadgets to see if any of their imagery has been * changed, and replaces their original imagery if they where changed. * Returns TRUE if any changes were made, FALSE otherwise. */ static int CheckGadgetList(theGadget) struct Gadget *theGadget; { int Changed = FALSE; while (theGadget) { switch(theGadget->GadgetType & ~GADGETTYPE) { case SIZING: Changed |= CheckGadget(theGadget,var(SizeImage),var(LR_SizeImage)); break; case WUPFRONT: case SUPFRONT: Changed |= CheckGadget(theGadget,var(UpFrontImage),var(LR_UpFrontImage)); break; case WDOWNBACK: case SDOWNBACK: Changed |= CheckGadget(theGadget,var(DownBackImage),var(LR_DownBackImage)); break; case CLOSE: Changed |= CheckGadget(theGadget,var(CloseImage),var(LR_CloseImage)); break; case BOOLGADGET: Changed |= CheckGadget(theGadget,var(ZoomImage),var(LR_ZoomImage)); break; } theGadget = theGadget->NextGadget; } return(Changed); } /* * CleanUpWindows() * * Looks through the intuition Screen and Window lists to see if * any gadgets are still using the NL gadget imagery. If so, * replace the old imagery and detail pen, then refresh the window * to show the original gadgets. Do this all in Forbid() mode, so * nothing changes while we're looking at the list. */ static void CleanUpWindows() { struct Screen *theScreen; struct Window *theWindow; int Changed; Forbid(); theScreen = IntuitionBase->FirstScreen; while (theScreen) { theWindow = theScreen->FirstWindow; while (theWindow) { Changed = CheckGadgetList(theWindow->FirstGadget); if (theWindow->BlockPen & PENCHANGED) { theWindow->BlockPen = STDBLOCKPEN; if (theWindow->DetailPen & PENCHANGED) theWindow->DetailPen = STDDETAILPEN; Changed = TRUE; } if (Changed) RefreshWindowFrame(theWindow); theWindow = theWindow->NextWindow; } Changed = CheckGadgetList(theScreen->FirstGadget); if (theScreen->BlockPen & PENCHANGED) { theScreen->BlockPen = STDBLOCKPEN; if (theScreen->DetailPen & PENCHANGED) theScreen->DetailPen = STDDETAILPEN; Changed = TRUE; } if (Changed) ShowTitle(theScreen,(theScreen->Flags & SHOWTITLE)? TRUE: FALSE); theScreen = theScreen->NextScreen; } if (var(Flags) & INTUITION_CHANGED) { InvertImage(IntuitionBase->CheckImage[0]); InvertImage(IntuitionBase->CheckImage[1]); InvertImage(IntuitionBase->AmigaIcon[0]); InvertImage(IntuitionBase->AmigaIcon[1]); var(Flags) &= ~INTUITION_CHANGED; } Permit(); } /* * Main() * * Look for the NL-Daemon port, which indicates that NL-Daemon already exists. * If the port does not exist, then NL-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 * Retro-fit any existing windows to include the NL gadgets * Notify the user that all is ready. * else (the port already exists, so NL-Daemon alreay is active) * Get the pointer to the NL_HandlerData structure from the port, * and get any variables we need from the structure. * Check that the loader versions are compatible. * Try to remove the SetFunction calls. * If successfull, then * Remove the port from the system list. * Cleanup and windows that are still using the image data * Unload the handler segment list. * Notify the user that NL-Daemon is deactivated. * Close Intuition. * else (we could not replace the functions) * Inform the user that NL-Daemon can not be removed */ void main(argc,argv) int argc; char **argv; { struct MsgPort *NamedPort; NamedPort = FindPort(PORTNAME); if (NamedPort == NULL) { CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV); LoadHandler(&NamedPort); AddPort(NamedPort); SetVariables(NamedPort,argc); SetVectors(NamedPort); 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 { if (UnSetVectors(NamedPort)) { RemPort(NamedPort); CleanUpWindows(); UnLoadSeg(var(Segment)); printf("%s removed\n",program); CloseLibrary(IntuitionBase); } else { printf("SetFunction vectors have been changed!\n"); printf("Cannot remove %s\n",program); } } } }