/* ** FracBlank - AmigaDOS 2.04 commodities utility screenblanker ** ** Copyright © 1991-1992 by Olaf `Olsen' Barthel ** All Rights Reserved ** ** Cosmic flame fractal code derived from xlock source code ** ** Copyright © 1988-1991 by Patrick J. Naughton. */ /* Include the specific math pragmas/header files here (is there * any way to figure this out by taking a look at undocumented * predefined compiler symbols?). */ #ifdef MATH_FFP #include #include #include #else #include #endif /* MATH_FFP */ #include /* sin -45° = cos -45° (saves precious calculation time). */ #define deg45 (-0.707106781) /* Use a simple address trick instead of the predefined * address in amiga.lib. */ #ifndef custom #define custom (*(struct Custom *)0xDFF000) #endif /* custom */ /* A couple of handy gadget control macros. */ #define GT_CHECKED(G) ((((struct Gadget *)(G)) -> Flags & GFLG_SELECTED) ? TRUE : FALSE) #define GT_STRING(G) (((struct StringInfo *)(((struct Gadget *)(G)) -> SpecialInfo)) -> Buffer) /* Hotkey IDs. */ enum { POP_WINDOW,BLANK_SCREEN }; /* Gadget IDs. */ enum { GAD_SCREENTIMEOUT,GAD_MOUSETIMEOUT,GAD_PATTERNCHANGE,GAD_HOTKEY, GAD_BLANKSCREEN,GAD_KEYBLANK,GAD_FRACTAL,GAD_COLOUR,GAD_HIDE,GAD_QUIT }; /* Some useful signals. */ #define SIG_BREAK SIGBREAKF_CTRL_C #define SIG_CHANGE SIGBREAKF_CTRL_D #define SIG_CYCLE SIGBREAKF_CTRL_E #define SIG_START SIGBREAKF_CTRL_F #define SIG_REFRESH SIGBREAKF_CTRL_E #define SIG_WAKEUP SIGBREAKF_CTRL_F #define SIG_CX (1 << CxPort -> mp_SigBit) #define SIG_WINDOW (Window ? (1 << Window -> UserPort -> mp_SigBit) : NULL) /* Private mouse blanker signals. */ #define SIG_NOTICE SIGBREAKF_CTRL_D #define SIG_ON SIGBREAKF_CTRL_E #define SIG_OFF SIGBREAKF_CTRL_F /* Number of patches to install. */ #define NUM_PATCHES (sizeof(PatchTable) / sizeof(struct PatchInfo)) /* Cosmic flame fractal parameters. */ #define MAXFLAMELEVEL 20 #define MAXTOTALPOINTS 20000 /* Fractal types. */ enum { FRACTAL_REAL_PLANE,FRACTAL_COSMIC_FLAME,FRACTAL_RANDOM }; /* Colour modes. */ enum { COLOUR_CYCLE,COLOUR_STATIC,COLOUR_MONO }; /* A system library patch definition. */ struct PatchInfo { APTR NewRoutine; LONG Offset; ULONG *Destination; }; /* A window identification node, also contains information * on the currently selected pointer sprite. */ struct WindowNode { struct MinNode Node; struct Window *Window; UWORD *Pointer; BYTE Height, Width; BYTE XOffset, YOffset; BYTE Off; }; /* The offsets of the system library routines we will patch. */ extern ULONG __far LVOClearPointer, LVOSetPointer, LVOOpenWindow, LVOOpenWindowTagList, LVOCloseWindow; /* Program revision tag. */ STATIC const UBYTE VersTag[] = "\0$VER: FracBlank 2.2 (4.4.92)"; /* Shared library identifiers. */ extern struct ExecBase *SysBase; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Library *CxBase, *IconBase, *GadToolsBase, *UtilityBase; /* The main program. */ struct Process *MainProcess; /* Blanker data. */ struct Task *BlankTask; struct Screen *BlankScreen; /* BlankerControl data. */ struct Task *BlankerControlTask; /* Mouse blanker data. */ struct Task *MouseBlankerTask; /* Commodities interface data. */ struct MsgPort *CxPort; CxObj *Broker; /* Gfx and gadtools data. */ struct Screen *DefaultScreen; APTR VisualInfo; struct TextFont *LocalFont; struct Gadget *GadgetList; struct Gadget *GadgetArray[GAD_QUIT + 1]; struct Window *Window; /* Window zoom data. */ struct IBox ZoomData = { -1,-1,-1,-1 }; /* Window dimensions. */ WORD WindowWidth = 284, WindowHeight = 113; /* Rainbow colour table. */ UWORD Table[75]; /* No colours at all. */ UWORD Black[32]; /* Declarations for cosmic flame blanker code. */ float Flame[2][3][2]; WORD FlameLevel, FlameAlternateForm, FlameModulo; UWORD FlameColourTable[32]; BYTE FlameWheel, FlameColour; PLANEPTR FlamePlane; ULONG FlamePoints; /* Key sequence buffers. */ UBYTE HotkeyBuffer[256], BlankScreenBuffer[256]; /* Screen and pattern change timeout. */ ULONG ScreenCount = 0, PatternCount = 0, ScreenTimeout = 60, MouseTimeout = 5, PatternTimeout = 60; /* A flag which tells us whether to blank the mouse pointer * on a keypress or not. */ BYTE KeyBlank = TRUE; /* Some kind of a semaphore to tell the blank task to stop drawing. */ BYTE StopDrawing = FALSE; /* The default font to be used by the control panel. */ struct TextAttr DefaultFont; UBYTE DefaultFontName[256]; UWORD DefaultFontWidth; /* The colours of a rainbow (well, with a bit of imagination, just * 32 colours in this rainbow for now). */ UWORD Rainbow[32] = { 0x0000,0x0F00,0x0F30,0x0F50, 0x0F70,0x0F90,0x0FB0,0x0FD0, 0x0FF0,0x0DF0,0x0BF0,0x09F0, 0x07F0,0x05F0,0x03F0,0x00F0, 0x00D1,0x00B3,0x0095,0x0077, 0x0059,0x003B,0x001D,0x000F, 0x010F,0x030F,0x050F,0x070F, 0x090F,0x0B0F,0x0D0F,0x0F0F }; /* A new broker definition, Commodities needs this. */ struct NewBroker NewBroker = { NB_VERSION, "FracBlanker", "Fractal Blanker v2.2", "Screen Blanker", NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE, 0,NULL,0 }; /* The fractal mode names. */ STRPTR FractalModes[] = { "Real Plane", "Cosmic Flame", "Random", NULL }; /* The current fractal type. */ UBYTE FractalType = FRACTAL_RANDOM; /* The colour mode names. */ STRPTR ColourModes[] = { "Cycling Colours", "Static Colours", "Monochrome", NULL }; /* The current colour mode. */ UBYTE ColourMode = COLOUR_CYCLE; /* Patch data. */ extern VOID __stdargs StackOldSetPointer(struct Window *Window,UWORD *Pointer,WORD Height,WORD Width,WORD XOffset,WORD YOffset); extern VOID NewSetPointer(VOID); APTR OldSetPointer; VOID (* __asm OldClearPointer)(register __a0 struct Window *,register __a6 struct IntuitionBase *); struct Window * (* __asm OldOpenWindowTagList)(register __a0 struct NewWindow *,register __a1 struct TagItem *,register __a6 struct IntuitionBase *); struct Window * (* __asm OldOpenWindow)(register __a0 struct NewWindow *,register __a6 struct IntuitionBase *); VOID (* __asm OldCloseWindow)(register __a0 struct Window *,register __a6 struct IntuitionBase *); /* Mouse blanker function prototypes. */ VOID __stdargs __saveds StackNewSetPointer(struct Window *Window,UWORD *Pointer,WORD Height,WORD Width,WORD XOffset,WORD YOffset); VOID __asm __saveds NewClearPointer(register __a0 struct Window *Window); struct Window * __asm __saveds NewOpenWindowTagList(register __a0 struct NewWindow *NewWindow,register __a1 struct TagItem *TagList); struct Window * __asm __saveds NewOpenWindow(register __a0 struct NewWindow *NewWindow); VOID __asm __saveds NewCloseWindow(register __a0 struct Window *Window); VOID __saveds MouseBlanker(VOID); VOID __regargs UpdateNode(struct WindowNode *Node,struct Window *Window); struct WindowNode * __regargs NewNode(struct Window *Window); VOID TurnOff(VOID); VOID TurnOn(VOID); /* The window and mouse pointer access list. */ struct SignalSemaphore WindowSemaphore; struct List WindowList; /* Miscellaneous mouse blanker counters and flags. */ ULONG KeyBlankUseCnt = 0, KeyBlankCount = 0; BYTE AllSpritesOff = FALSE, KeyBlankStop = FALSE; /* The table of patches to install. */ struct PatchInfo PatchTable[] = { NewClearPointer, (LONG)&LVOClearPointer, (ULONG *)&OldClearPointer, NewSetPointer, (LONG)&LVOSetPointer, (ULONG *)&OldSetPointer, NewOpenWindowTagList, (LONG)&LVOOpenWindowTagList, (ULONG *)&OldOpenWindowTagList, NewOpenWindow, (LONG)&LVOOpenWindow, (ULONG *)&OldOpenWindow, NewCloseWindow, (LONG)&LVOCloseWindow, (ULONG *)&OldCloseWindow }; /* An entirely transparent sprite. */ UWORD __chip BlankSprite[(2 + 1) * 2] = { 0x0000,0x0000, 0x0000,0x0000, 0x0000,0x0000 }; /* Function prototypes. */ extern VOID __asm MonoPlot(register __a0 PLANEPTR Plane,register __d0 WORD x,register __d1 WORD y,register __d2 UWORD Modulo,register __d3 WORD MaxX,register __d4 WORD MaxY); extern VOID __asm MultiPlot(register __a0 struct Screen *,register __d0 WORD X,register __d1 WORD Y,register __d2 WORD Colour); extern __stdargs SPrintf(STRPTR Mem,STRPTR Args,...); extern LONG __asm Atol(register __a0 STRPTR String); VOID __saveds BlankerControl(VOID); ULONG __regargs Random(ULONG MaxValue); VOID RealPlane(VOID); VOID CosmicFlame(VOID); BYTE RecurseMono(float x,float y,WORD Level); BYTE RecurseColour(float x,float y,WORD Level); VOID __saveds Blanker(VOID); VOID __saveds __stdargs BlankerAction(CxMsg *CxMessage,CxObj *CxObject); VOID ShutdownCx(VOID); BYTE __regargs SetupCx(STRPTR *ToolTypes); VOID __regargs HandleCxMsg(CxMsg *Message); LONG __saveds __stdargs ShowTime(struct Gadget *SomeGadget,WORD Level); struct Gadget * CreateAllGadgets(struct Gadget **GadgetArray,struct Gadget **GadgetList,APTR VisualInfo,UWORD TopEdge); VOID ShutdownWindow(VOID); VOID __regargs CentreWindow(struct Screen *Screen,WORD *LeftEdge,WORD *TopEdge); BYTE SetupWindow(VOID); VOID __regargs CloseAll(LONG ReturnCode); VOID __regargs OpenAll(int argc,char **argv); VOID __stdargs main(int argc,char **argv); /* MouseBlanker(): * * The mouse pointer blanker task, patches a few system library functions * and turns the mouse pointer on and off. */ VOID __saveds MouseBlanker() { struct Wedge *WedgeTable; /* Create the wedge table, note: this memory will never be * freed! */ if(WedgeTable = (struct Wedge *)AllocMem(sizeof(struct Wedge) * NUM_PATCHES,MEMF_PUBLIC | MEMF_CLEAR)) { struct WindowNode *Node, *Next; ULONG IntuiLock, SignalSet; struct Screen *Screen; struct Window *Window; BYTE Terminated = FALSE; WORD i; /* Set up the window list data. */ InitSemaphore(&WindowSemaphore); NewList(&WindowList); /* Put all windows into the list. */ IntuiLock = LockIBase(NULL); Screen = IntuitionBase -> FirstScreen; while(Screen) { Window = Screen -> FirstWindow; while(Window) { NewNode(Window); Window = Window -> NextWindow; } Screen = Screen -> NextScreen; } Forbid(); UnlockIBase(IntuiLock); /* Install the patches. */ for(i = 0 ; i < NUM_PATCHES ; i++) { WedgeTable[i] . Command = JMP_ABS; WedgeTable[i] . Address = PatchTable[i] . NewRoutine; *PatchTable[i] . Destination = (ULONG)SetFunction((struct Library *)IntuitionBase,PatchTable[i] . Offset,(APTR)&WedgeTable[i]); } CacheClearU(); /* Ring back. */ Signal(MainProcess,SIG_WAKEUP); Permit(); /* Loop until terminated. */ while(!Terminated) { /* Wait for a signal. */ SignalSet = Wait(SIG_BREAK | SIG_ON | SIG_OFF); /* Are we to quit? */ if(SignalSet & SIG_BREAK) Terminated = TRUE; /* Are we to turn the mouse pointer sprite back on? */ if(SignalSet & SIG_ON) TurnOn(); /* Are we to turn all mouse pointer sprites off? */ if(SignalSet & SIG_OFF) TurnOff(); } Forbid(); /* Clear the notification signal. */ SetSignal(0,SIG_NOTICE); /* Do not continue adding new nodes to the list. */ KeyBlankStop = TRUE; Permit(); /* Turn all sprites back on. */ TurnOn(); /* Remove the patches. */ Forbid(); for(i = 0 ; i < NUM_PATCHES ; i++) WedgeTable[i] . Address = (APTR)*PatchTable[i] . Destination; CacheClearU(); Permit(); /* Loop until all patched routines are clear. */ while(KeyBlankUseCnt > 0) Wait(SIG_NOTICE); /* Remove all windows from the list. */ Node = (struct WindowNode *)WindowList . lh_Head; while(Next = (struct WindowNode *)Node -> Node . mln_Succ) { Remove((struct Node *)Node); FreeVec(Node); Node = Next; } } /* We're done now. */ Forbid(); Signal(MainProcess,SIG_WAKEUP); } /* UpdateNode(struct WindowNode *Node,struct Window *Window): * * Update a window node with the new pointer data. */ VOID __regargs UpdateNode(struct WindowNode *Node,struct Window *Window) { Node -> Pointer = Window -> Pointer; Node -> Height = Window -> PtrHeight; Node -> Width = Window -> PtrWidth; Node -> XOffset = Window -> XOffset; Node -> YOffset = Window -> YOffset; } /* NewNode(struct Window *Window): * * Create a new window node and link it into the window list. */ struct WindowNode * __regargs NewNode(struct Window *Window) { struct WindowNode *Node; if(Node = (struct WindowNode *)AllocVec(sizeof(struct WindowNode),MEMF_PUBLIC | MEMF_CLEAR)) { Node -> Window = Window; UpdateNode(Node,Window); AddTail(&WindowList,(struct Node *)Node); } return(Node); } /* FindWindow(struct Window *Window): * * Find a window within the window list. */ struct WindowNode * __regargs FindWindow(struct Window *Window) { struct WindowNode *Node, *Next; Node = (struct WindowNode *)WindowList . lh_Head; while(Next = (struct WindowNode *)Node -> Node . mln_Succ) { if(Window == Node -> Window) return(Node); Node = Next; } return(NULL); } /* TurnOff(): * * Turn all mouse pointer sprites in all windows off. */ VOID TurnOff() { /* Gain access to the window semaphore. */ ObtainSemaphore(&WindowSemaphore); /* Are all sprites still turned off? */ if(!AllSpritesOff) { struct WindowNode *Node, *Next; /* Walk through the window list... */ Node = (struct WindowNode *)WindowList . lh_Head; while(Next = (struct WindowNode *)Node -> Node . mln_Succ) { /* Is this mouse pointer still active? */ if(!Node -> Off) { /* Update the node entry. */ UpdateNode(Node,Node -> Window); /* Change the pointer. */ StackOldSetPointer(Node -> Window,BlankSprite,1,16,0,0); Node -> Off = TRUE; } Node = Next; } AllSpritesOff = TRUE; } ReleaseSemaphore(&WindowSemaphore); } /* TurnOn(): * * Turn all mouse pointer sprites in all windows back on. */ VOID TurnOn() { struct WindowNode *Node, *Next; ObtainSemaphore(&WindowSemaphore); AllSpritesOff = FALSE; KeyBlankCount = 0; Node = (struct WindowNode *)WindowList . lh_Head; while(Next = (struct WindowNode *)Node -> Node . mln_Succ) { if(Node -> Off) { if(Node -> Pointer) StackOldSetPointer(Node -> Window,Node -> Pointer,Node -> Height,Node -> Width,Node -> XOffset,Node -> YOffset); else OldClearPointer(Node -> Window,IntuitionBase); Node -> Off = FALSE; } Node = Next; } ReleaseSemaphore(&WindowSemaphore); } /* NewClearPointer(register __a0 struct Window *Window): * * Patch: resets the mouse pointer of a window * back to its default shape. */ VOID __asm __saveds NewClearPointer(register __a0 struct Window *Window) { if(KeyBlankStop) OldClearPointer(Window,IntuitionBase); else { struct WindowNode *Node; ObtainSemaphore(&WindowSemaphore); KeyBlankUseCnt++; if(Node = FindWindow(Window)) { if(!AllSpritesOff) { OldClearPointer(Window,IntuitionBase); Node -> Off = FALSE; } else Node -> Off = TRUE; Node -> Pointer = NULL; } else OldClearPointer(Window,IntuitionBase); KeyBlankUseCnt--; Signal(MouseBlankerTask,SIG_NOTICE); ReleaseSemaphore(&WindowSemaphore); } } /* StackNewSetPointer(): * * Patch: attach a new mouse pointer sprite to a window. */ VOID __stdargs __saveds StackNewSetPointer(struct Window *Window,UWORD *Pointer,WORD Height,WORD Width,WORD XOffset,WORD YOffset) { if(KeyBlankStop) StackOldSetPointer(Window,Pointer,Height,Width,XOffset,YOffset); else { struct WindowNode *Node; ObtainSemaphore(&WindowSemaphore); KeyBlankUseCnt++; if(Node = FindWindow(Window)) { if(!AllSpritesOff) { StackOldSetPointer(Window,Pointer,Height,Width,XOffset,YOffset); Node -> Off = FALSE; } else Node -> Off = TRUE; Node -> Pointer = Pointer; Node -> Height = Height; Node -> Width = Width; Node -> XOffset = XOffset; Node -> YOffset = YOffset; } else StackOldSetPointer(Window,Pointer,Height,Width,XOffset,YOffset); KeyBlankUseCnt--; Signal(MouseBlankerTask,SIG_NOTICE); ReleaseSemaphore(&WindowSemaphore); } } /* NewOpenWindowTagList(): * * Patch: open a new window. */ struct Window * __asm __saveds NewOpenWindowTagList(register __a0 struct NewWindow *NewWindow,register __a1 struct TagItem *TagList) { struct NewWindow OtherWindow; if(NewWindow) { if((NewWindow -> Type & SCREENTYPE) == CUSTOMSCREEN && NewWindow -> Screen == BlankScreen) { CopyMem(NewWindow,&OtherWindow,sizeof(struct NewWindow)); NewWindow = &OtherWindow; NewWindow -> Type = (NewWindow -> Type & ~SCREENTYPE) | WBENCHSCREEN; NewWindow -> Screen = NULL; Signal(MouseBlankerTask, SIG_ON); Signal(BlankerControlTask, SIG_BREAK); } } if(KeyBlankStop) return(OldOpenWindowTagList(NewWindow,TagList,IntuitionBase)); else { struct Window *Window; ULONG Signals; ObtainSemaphore(&WindowSemaphore); KeyBlankUseCnt++; if(Window = OldOpenWindowTagList(NewWindow,TagList,IntuitionBase)) { NewNode(Window); Signals = SIG_NOTICE | SIG_ON; } else Signals = SIG_NOTICE; KeyBlankUseCnt--; Signal(MouseBlankerTask,Signals); ReleaseSemaphore(&WindowSemaphore); return(Window); } } /* NewOpenWindow(): * * Patch: open a new window. */ struct Window * __asm __saveds NewOpenWindow(register __a0 struct NewWindow *NewWindow) { struct NewWindow OtherWindow; if(NewWindow) { if((NewWindow -> Type & SCREENTYPE) == CUSTOMSCREEN && NewWindow -> Screen == BlankScreen) { CopyMem(NewWindow,&OtherWindow,sizeof(struct NewWindow)); NewWindow = &OtherWindow; NewWindow -> Type = (NewWindow -> Type & ~SCREENTYPE) | WBENCHSCREEN; NewWindow -> Screen = NULL; Signal(MouseBlankerTask, SIG_ON); Signal(BlankerControlTask, SIG_BREAK); } } if(KeyBlankStop) return(OldOpenWindow(NewWindow,IntuitionBase)); else { struct Window *Window; ULONG Signals; ObtainSemaphore(&WindowSemaphore); KeyBlankUseCnt++; if(Window = OldOpenWindow(NewWindow,IntuitionBase)) { NewNode(Window); Signals = SIG_NOTICE | SIG_ON; } else Signals = SIG_NOTICE; KeyBlankUseCnt--; Signal(MouseBlankerTask,Signals); ReleaseSemaphore(&WindowSemaphore); return(Window); } } /* NewCloseWindow(): * * Patch: close a window. */ VOID __asm __saveds NewCloseWindow(register __a0 struct Window *Window) { struct WindowNode *Node; ObtainSemaphore(&WindowSemaphore); KeyBlankUseCnt++; if(Node = FindWindow(Window)) { Remove((struct Node *)Node); FreeVec(Node); } OldCloseWindow(Window,IntuitionBase); KeyBlankUseCnt--; Signal(MouseBlankerTask,SIG_NOTICE); ReleaseSemaphore(&WindowSemaphore); } /* BlankerControl(): * * The screen blanker control task. */ VOID __saveds BlankerControl() { ULONG SignalSet; Forbid(); FOREVER { SignalSet = Wait(SIG_BREAK | SIG_START | SIG_CHANGE | SIG_REFRESH); /* Remove both the screen and the blanker task? */ if(SignalSet & SIG_BREAK) { if(BlankScreen) ScreenToBack(BlankScreen); /* Remove the blanker task. */ if(BlankTask) { struct Task *Task = BlankTask; /* Remember the old address and clear it. */ BlankTask = NULL; /* Make sure that the break signal is * not set when we are waiting for a * handshake. */ SetSignal(0,SIG_BREAK); /* Tell the blanker task to shut down. */ Signal(Task,SIG_BREAK); /* Move the blanker task priority up. */ SetTaskPri(Task,80); /* Wait for handshake signal... */ Wait(SIG_BREAK); } /* Close the blanker screen. */ if(BlankScreen) { struct Screen *Screen = BlankScreen; BlankScreen = NULL; #ifdef USE_COP_LIST FreeVPortCopLists(&Screen -> ViewPort); RethinkDisplay(); #endif /* USE_COP_LIST */ CloseScreen(Screen); } continue; } /* Start the screen blanker? */ if(SignalSet & SIG_START) { if(!BlankScreen) { struct Screen *Screen, *FirstScreen; ULONG DisplayID, Mode, IntuiLock; /* Gain access to IntuitionBase. */ IntuiLock = LockIBase(NULL); /* Determine the first screen. */ FirstScreen = IntuitionBase -> FirstScreen; /* Inquire the display mode the first * screen is in. */ DisplayID = GetVPModeID(&FirstScreen -> ViewPort); /* Surrender the lock. */ UnlockIBase(IntuiLock); /* Set the approriate display mode. */ if(ColourMode == COLOUR_MONO) Mode = HIRESLACE_KEY; else Mode = EXTRAHALFBRITELACE_KEY; /* This feature has been added for users * of old Multiscan monitors which take * ages to synchronize with different * display modes. The programm will try * to open the blanker screen in the same * display mode as the first screen is in. * Note that this trick will fail to work * in ECS screen modes (productivity, * superhires, etc.). */ switch(DisplayID & MONITOR_ID_MASK) { case NTSC_MONITOR_ID: Mode |= NTSC_MONITOR_ID; break; case PAL_MONITOR_ID: Mode |= PAL_MONITOR_ID; break; default: Mode |= DEFAULT_MONITOR_ID; break; } if(Screen = OpenScreenTags(NULL, SA_Behind, TRUE, SA_Quiet, TRUE, SA_DisplayID, Mode, SA_Overscan, OSCAN_MAX, SA_Depth, ColourMode == COLOUR_MONO ? 1 : 6, TAG_DONE)) { #ifdef USE_COP_LIST struct UCopList *UserCopperList; /* I had a lot of problems trying to shut down * the sprite display hardware completely. * The mouse pointer would pop up again after * a certain time interval, no matter what I * did. * * Now, Amy, you had your chance, hadn't you? * * This is the big one: a user copper list will * shut down the sprite hardware. Full stop. */ if(UserCopperList = (struct UCopList *)AllocMem(sizeof(struct UCopList),MEMF_PUBLIC|MEMF_CLEAR)) { /* Set up for 3 instructions. */ if(UCopperListInit(UserCopperList,3)) { /* Wait for first line. */ CWAIT(UserCopperList,0,0); /* Disable sprite DMA. */ CMOVE(UserCopperList,custom . dmacon,BITCLR|DMAF_SPRITE); /* Terminate copper instruction list. */ CEND(UserCopperList); /* Install the copper list. */ Screen -> ViewPort . UCopIns = UserCopperList; /* Link it into the screen copper list. */ RethinkDisplay(); /* Set the colours to black. */ #endif /* USE_COP_LIST */ LoadRGB4(&Screen -> ViewPort,Black,32); /* Display the screen. */ ScreenToFront(Screen); BlankScreen = Screen; #ifdef USE_COP_LIST } else { CloseScreen(Screen); FreeMem(UserCopperList,sizeof(struct UCopList)); } } else CloseScreen(Screen); #endif /* USE_COP_LIST */ } } if(BlankScreen) { PatternCount = 0; if(!BlankTask) BlankTask = (struct Task *)CreateTask("FracBlank Blanker Task",-20,Blanker,1024 * MAXFLAMELEVEL); } continue; } /* Bring the screen to the front? */ if(SignalSet & SIG_REFRESH) { if(BlankScreen) { /* Push the blanker screen to the front if necessary. */ if(BlankScreen -> TopEdge > 0) MoveScreen(BlankScreen,0,-BlankScreen -> TopEdge); if(IntuitionBase -> FirstScreen != BlankScreen) ScreenToFront(BlankScreen); } } /* Change the patterns? */ if(SignalSet & SIG_CHANGE) { /* Stop drawing patterns. */ StopDrawing = TRUE; if(BlankScreen && BlankTask) { /* Clear the screen. */ LoadRGB4(&BlankScreen -> ViewPort,Black,32); /* Then tell the blanker to restart. */ Signal(BlankTask,SIG_CHANGE); } } } } /* Random(ULONG MaxValue): * * Simple random number generation routine. */ ULONG __regargs Random(ULONG MaxValue) { STATIC ULONG RandomSeed = 0xDEAD0123; RandomSeed = RandomSeed * custom . vhposr + 0xE153766F; return(RandomSeed % MaxValue); } /* RealPlane(): * * Draw real plane fractals. */ VOID RealPlane() { STATIC BYTE Wheel = 0; UWORD Colours[32],OffsetX = BlankScreen -> Width >> 1,OffsetY = BlankScreen -> Height >> 1; float x = 0,y = 0,yy,a,b,c,sx,sy,mag; /* Are we running in monochrome mode? */ if(ColourMode == COLOUR_MONO) { UWORD Modulo = BlankScreen -> RastPort . BitMap -> BytesPerRow; PLANEPTR Plane = BlankScreen -> RastPort . BitMap -> Planes[0]; /* Provide starting numbers for the fractal * parameters. */ a = (float)(Random(700) + 5) / 100; b = (float)(Random(190) + 5) / 100; c = (float)(Random( 90) + 5) / 100; mag = (float)(1 << (Random(6) + 2)) * deg45; /* Set up the screen colour table. */ Colours[0] = 0; Colours[1] = Table[Wheel]; LoadRGB4(&BlankScreen -> ViewPort,Colours,2); /* Go into fractal generation loop. */ FOREVER { /* Are we to shut down? */ if(SetSignal(0,0) & SIG_BREAK) { Forbid(); Signal(BlankerControlTask,SIG_BREAK); RemTask(SysBase -> ThisTask); } /* The original formula looks like * this: * ½ * x = y - SIGN(x) × ABS(b × x - c) * y = a - x * * I have split the calculation into * several steps to save time and * variables. */ yy = a - x; if(x < 0) x = y + sqrt(fabs(b * x - c)); else x = y - sqrt(fabs(b * x - c)); y = yy; /* The resulting image appears to have * been rotated by 45°, so we'll * rotate the pixel coordinates by -45° * * x = x × cos(alpha) + y × sin(alpha) * y = -x × sin(alpha) + y × cos(alpha) * * We also magnify the image (i.e. the * distribution of pixels) in the following * lines. */ sx = mag * ( x + y); sy = mag * (-x + y); /* If the pixel happens to reside within * the boundaries of the screen, draw it. */ MonoPlot(Plane,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY,Modulo,BlankScreen -> Width,BlankScreen -> Height); /* ^E tells the blanker to rotate the * colours. */ if(SetSignal(0,0) & SIG_CYCLE) { SetSignal(0,SIG_CYCLE); Colours[1] = Table[Wheel]; LoadRGB4(&BlankScreen -> ViewPort,Colours,2); Wheel = (Wheel + 1) % 75; } /* Change the pattern? */ if(SetSignal(0,0) & SIG_CHANGE) { SetSignal(0,SIG_CHANGE); SetRast(&BlankScreen -> RastPort,0); LoadRGB4(&BlankScreen -> ViewPort,Colours,2); StopDrawing = FALSE; x = y = 0; a = (float)(Random(700) + 5) / 100; b = (float)(Random(190) + 5) / 100; c = (float)(Random( 90) + 5) / 100; mag = (float)(1 << (Random(6) + 2)) * deg45; } } } else { struct RastPort *RPort; UWORD Count = 0; WORD i,NewBit = 0; BYTE Colour = 1,Plus = 1; a = (float)(Random(700) + 5) / 100; b = (float)(Random(190) + 5) / 100; c = (float)(Random( 90) + 5) / 100; mag = (float)(1 << (Random(6) + 2)) * deg45; Colours[0] = 0x000; for(i = 1 ; i < 32 ; i++) Colours[i] = Table[(Wheel + i) % 75]; if(ColourMode == COLOUR_CYCLE) LoadRGB4(&BlankScreen -> ViewPort,Colours,32); else LoadRGB4(&BlankScreen -> ViewPort,Rainbow,32); Wheel = (Wheel + 1) % 75; RPort = &BlankScreen -> RastPort; FOREVER { /* Are we to shut down? */ if(SetSignal(0,0) & SIG_BREAK) { Forbid(); Signal(BlankerControlTask,SIG_BREAK); RemTask(SysBase -> ThisTask); } yy = a - x; if(x < 0) x = y + sqrt(fabs(b * x - c)); else x = y - sqrt(fabs(b * x - c)); y = yy; sx = mag * ( x + y); sy = mag * 2.0 * (-x + y); MultiPlot(BlankScreen,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY,Colour | NewBit); /* Oh well, it's not that easy to * produce decent colour values for * the pixels to be rendered. * * The following statement will change * the current drawing pen after exactly * 1200 pixels have been rendered and will * pick a new colour between 1 and 31. */ if(Count++ >= 1200) { Count = 0; if(NewBit) { NewBit = 0; Colour += Plus; if(!Colour) { Plus = 1; Colour = 2; } else { if(Colour == 32) { Plus = -1; Colour = 30; } } } else NewBit = 0x20; } if(SetSignal(0,0) & SIG_CYCLE) { SetSignal(0,SIG_CYCLE); for(i = 1 ; i < 32 ; i++) Colours[i] = Table[(Wheel + i) % 75]; if(ColourMode == COLOUR_CYCLE) LoadRGB4(&BlankScreen -> ViewPort,Colours,32); Wheel = (Wheel + 1) % 75; } if(SetSignal(0,0) & SIG_CHANGE) { SetSignal(0,SIG_CHANGE); SetRast(RPort,0); StopDrawing = FALSE; if(ColourMode == COLOUR_CYCLE) LoadRGB4(&BlankScreen -> ViewPort,Colours,32); else LoadRGB4(&BlankScreen -> ViewPort,Rainbow,32); x = y = 0; a = (float)(Random(700) + 5) / 100; b = (float)(Random(190) + 5) / 100; c = (float)(Random( 90) + 5) / 100; mag = (float)(1 << (Random(6) + 2)) * deg45; } } } } /* RecurseMono(float x,float y,WORD Level): * * Cosmic flame calculation routine (monochrome). */ BYTE RecurseMono(float x,float y,WORD Level) { /* Are we to shut down? */ if(SetSignal(0,0) & SIG_BREAK) { Forbid(); Signal(BlankerControlTask,SIG_BREAK); RemTask(SysBase -> ThisTask); } if(StopDrawing) { FlameLevel = 0; StopDrawing = FALSE; return(FALSE); } /* Change the pattern? */ if(SetSignal(0,0) & SIG_CHANGE) { SetSignal(0,SIG_CHANGE); FlameLevel = 0; StopDrawing = FALSE; return(FALSE); } /* ^E tells the blanker to rotate the * colours. */ if(SetSignal(0,0) & SIG_CYCLE) { SetSignal(0,SIG_CYCLE); FlameColourTable[1] = Table[FlameWheel]; LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,2); FlameWheel = (FlameWheel + 1) % 75; } if(Level >= MAXFLAMELEVEL) { if((FlamePoints++) > MAXTOTALPOINTS) return(FALSE); else MonoPlot(FlamePlane,(WORD)((BlankScreen -> Width >> 1) * (x + 1.0)),(WORD)((BlankScreen -> Height >> 1) * (y + 1.0)),FlameModulo,BlankScreen -> Width,BlankScreen -> Height); } else { float nx,ny; WORD i; for(i = 0 ; i < 2 ; i++) { nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i]; ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i]; if(i < FlameAlternateForm) { nx = sin(nx); ny = sin(ny); } if(!StopDrawing) { if(!RecurseMono(nx,ny,Level + 1)) return(FALSE); } else return(FALSE); } } return(TRUE); } /* RecurseColour(float x,float y,WORD Level): * * Cosmic flame calculation routine (colour). */ BYTE RecurseColour(float x,float y,WORD Level) { /* Are we to shut down? */ if(SetSignal(0,0) & SIG_BREAK) { Forbid(); Signal(BlankerControlTask,SIG_BREAK); RemTask(SysBase -> ThisTask); } if(StopDrawing) { FlameLevel = 0; StopDrawing = FALSE; return(FALSE); } /* Change the pattern? */ if(SetSignal(0,0) & SIG_CHANGE) { SetSignal(0,SIG_CHANGE); FlameLevel = 0; StopDrawing = FALSE; return(FALSE); } /* ^E tells the blanker to rotate the * colours. */ if(SetSignal(0,0) & SIG_CYCLE) { SetSignal(0,SIG_CYCLE); if(ColourMode == COLOUR_CYCLE) { WORD i; for(i = 1 ; i < 32 ; i++) FlameColourTable[i] = Table[(FlameWheel + i) % 75]; LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,32); FlameWheel = (FlameWheel + 1) % 75; } } if(Level >= MAXFLAMELEVEL) { if((FlamePoints++) > MAXTOTALPOINTS) return(FALSE); else MultiPlot(BlankScreen,(WORD)((BlankScreen -> Width >> 1) * (x + 1.0)),(WORD)((BlankScreen -> Height >> 1) * (y + 1.0)),FlameColour + 1); } else { float nx,ny; WORD i; for(i = 0 ; i < 2 ; i++) { nx = Flame[0][0][i] * x + Flame[0][1][i] * y + Flame[0][2][i]; ny = Flame[1][0][i] * x + Flame[1][1][i] * y + Flame[1][2][i]; if(i < FlameAlternateForm) { nx = sin(nx); ny = sin(ny); } if(!StopDrawing) { if(!RecurseColour(nx,ny,Level + 1)) return(FALSE); } else return(FALSE); } } return(TRUE); } /* CosmicFlame(): * * The cosmic flame screen blanker. * * xlock.c - X11 client to lock a display and show a screen saver. * * Copyright (c) 1988-91 by Patrick J. Naughton. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. */ VOID CosmicFlame() { WORD i,j,k; /* Monochrome mode? */ if(ColourMode == COLOUR_MONO) { BYTE Alternate = FALSE; /* Initialize defaults. */ FlameModulo = BlankScreen -> RastPort . BitMap -> BytesPerRow; FlamePlane = BlankScreen -> RastPort . BitMap -> Planes[0]; FlameWheel = 0; /* Set up the screen colour table. */ FlameColourTable[0] = 0; FlameColourTable[1] = Table[FlameWheel]; LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,2); FlameLevel = 0; /* Go into fractal generation loop. */ FOREVER { if(!((FlameLevel++) % 20)) { LoadRGB4(&BlankScreen -> ViewPort,Black,2); SetRast(&BlankScreen -> RastPort,0); LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,2); Alternate = !Alternate; } if(Alternate) FlameAlternateForm = 0; else FlameAlternateForm = Random(2) + 2; for(k = 0 ; k < 2 ; k++) { for(i = 0 ; i < 2 ; i++) { for(j = 0; j < 3; j++) Flame[i][j][k] = ((float)Random(1024)) / 512.0 - 1.0; } } FlamePoints = 0; RecurseMono(0.0,0.0,0); } } else { BYTE Alternate = FALSE,Plus; FlameWheel = Random(75); FlameColourTable[0] = 0x000; for(i = 1 ; i < 32 ; i++) FlameColourTable[i] = Table[(FlameWheel + i) % 75]; if(ColourMode == COLOUR_CYCLE) LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,32); else LoadRGB4(&BlankScreen -> ViewPort,Rainbow,32); FlameWheel = (FlameWheel + 1) % 75; FlameColour = Random(63); Plus = 1; FlameLevel = 0; /* Go into fractal generation loop. */ FOREVER { if(!((FlameLevel++) % 20)) { LoadRGB4(&BlankScreen -> ViewPort,Black,32); SetRast(&BlankScreen -> RastPort,0); if(ColourMode == COLOUR_CYCLE) LoadRGB4(&BlankScreen -> ViewPort,FlameColourTable,32); else LoadRGB4(&BlankScreen -> ViewPort,Rainbow,32); Alternate = !Alternate; } else { if(FlameColour == 62) Plus = -1; if(FlameColour == 0) Plus = 1; FlameColour += Plus; } if(Alternate) FlameAlternateForm = 0; else FlameAlternateForm = Random(2) + 2; for(k = 0 ; k < 2 ; k++) { for(i = 0 ; i < 2 ; i++) { for(j = 0; j < 3; j++) Flame[i][j][k] = ((float)Random(1024)) / 512.0 - 1.0; } } FlamePoints = 0; RecurseColour(0.0,0.0,0); } } } /* Blanker(): * * The screen blanker itself. */ VOID __saveds Blanker() { /* Determine fractal type. */ if(FractalType == FRACTAL_COSMIC_FLAME) CosmicFlame(); else { if(FractalType == FRACTAL_REAL_PLANE) RealPlane(); else { if(Random(42) >= 21) CosmicFlame(); else RealPlane(); } } /* Quietly remove ourselves. */ Forbid(); BlankTask = NULL; } /* BlankerAction(CxMsg *CxMessage,CxObj *CxObject): * * Commodities support routine, handles the Commodities * custom actions (in this case: filter the InputEvents * coming in and enable/disable the screen blanker). */ VOID __saveds __stdargs BlankerAction(CxMsg *CxMessage,CxObj *CxObject) { STATIC BYTE Count = 0; struct InputEvent *Event = (struct InputEvent *)CxMsgData(CxMessage); /* Push the blanker screen to the front if necessary. */ if(BlankScreen) Signal(BlankerControlTask,SIG_REFRESH); /* This looks like a timer event. */ if(Event -> ie_Class == IECLASS_TIMER) { if(KeyBlankCount++ >= MouseTimeout * 10) { KeyBlankCount = 0; if(MouseTimeout) Signal(MouseBlankerTask,SIG_OFF); } if(!Window) { /* Screen blanker still inactive? */ if(!BlankTask) { /* Is there a timeout to take care of? */ if(ScreenTimeout) { /* Are we ready to create the * screenblanker? */ if(ScreenCount++ >= ScreenTimeout * 10) Signal(BlankerControlTask,SIG_START); } } else { /* Every 5/60 second we signal the blanker * task to rotate the palette. */ if(Count++ >= 2) { Signal(BlankTask,SIG_CYCLE); Count = 0; } /* Is it time to change the pattern? */ if(PatternTimeout) { if(PatternCount++ >= PatternTimeout * 10) { Signal(BlankerControlTask,SIG_CHANGE); PatternCount = 0; } } } } } else { /* The following lines determine whether * the blanker is to be removed or to * be left running. */ switch(Event -> ie_Class) { case IECLASS_RAWKEY: if(!(Event -> ie_Code & IECODE_UP_PREFIX) && !(Event -> ie_Qualifier & IEQUALIFIER_REPEAT)) { if(KeyBlank) Signal(MouseBlankerTask,SIG_OFF); Signal(BlankerControlTask,SIG_BREAK); } break; case IECLASS_NEWPOINTERPOS: case IECLASS_POINTERPOS: case IECLASS_RAWMOUSE: Signal(MouseBlankerTask,SIG_ON); Signal(BlankerControlTask,SIG_BREAK); break; default: break; } ScreenCount = 0; } } /* ShutdownCx(): * * Close the Commodities interface. */ VOID ShutdownCx() { if(CxPort) { struct Message *Message; /* Remove the broker. */ if(Broker) DeleteCxObjAll(Broker); /* Remove the MsgPort from the public list. */ RemPort(CxPort); /* Remove all pending messages. */ while(Message = GetMsg(CxPort)) ReplyMsg(Message); /* Delete the MsgPort. */ DeleteMsgPort(CxPort); CxPort = NULL; Broker = NULL; } } /* GetSeconds(STRPTR String): * * Calculates the number of seconds corresponding to * expressions such as `11:25' or `10'. */ WORD GetSeconds(STRPTR String) { WORD i,Seconds; for(i = strlen(String) - 1 ; i >= 0 ; i--) { if(String[i] == ':') { Seconds = Atol(&String[i + 1]); String[i] = 0; Seconds += 60 * Atol(String); if(Seconds > 30 * 60) Seconds = 30 * 60; return(Seconds); } } if((Seconds = Atol(String)) > 30 * 60) Seconds = 30 * 60; return(Seconds); } /* SetupCx(STRPTR *ToolTypes): * * Set up the Commodities interface. */ BYTE __regargs SetupCx(STRPTR *ToolTypes) { /* Cancel any previously made assignments. */ ShutdownCx(); /* Create a reply port. */ if(CxPort = CreateMsgPort()) { /* Fill in a unique name. */ CxPort -> mp_Node . ln_Name = NewBroker . nb_Name; /* Add the reply port to the public list. */ AddPort(CxPort); /* Install the replyport. */ NewBroker . nb_Port = CxPort; /* Set the Commodity priority if possible. */ if(ToolTypes) NewBroker . nb_Pri = ArgInt(ToolTypes,"CX_PRIORITY",0); /* Create the broker. */ if(Broker = CxBroker(&NewBroker,NULL)) { CxObj *ObjectList; UBYTE *String,Buffer[256]; if(ToolTypes) { /* Set the Commodity popup hotkey if possible. */ String = ArgString(ToolTypes,"CX_POPKEY","shift f1"); strcpy(HotkeyBuffer,String); /* Determine the screen blanker hotkey. */ String = ArgString(ToolTypes,"BLANKSCREEN","shift f2"); strcpy(BlankScreenBuffer,String); /* Which fractal type? */ String = ArgString(ToolTypes,"FRACTAL","RANDOM"); if(!Stricmp(String,"REALPLANE") || !Stricmp(String,"REAL")) FractalType = FRACTAL_REAL_PLANE; else { if(!Stricmp(String,"COSMICFLAME") || !Stricmp(String,"FLAME")) FractalType = FRACTAL_COSMIC_FLAME; else FractalType = FRACTAL_RANDOM; } /* Which colour mode? */ String = ArgString(ToolTypes,"COLOUR","CYCLE"); if(!Stricmp(String,"STATIC")) ColourMode = COLOUR_STATIC; else { if(!Stricmp(String,"MONO")) ColourMode = COLOUR_MONO; else ColourMode = COLOUR_CYCLE; } /* Adjust the screen timeout if possible. */ strcpy(Buffer,ArgString(ToolTypes,"SCREENTIMEOUT","1:00")); ScreenTimeout = GetSeconds(Buffer); /* Adjust the pattern change timeout if possible. */ strcpy(Buffer,ArgString(ToolTypes,"PATTERNTIMEOUT","1:00")); PatternTimeout = GetSeconds(Buffer); /* Adjust the mouse timeout if possible. */ strcpy(Buffer,ArgString(ToolTypes,"MOUSETIMEOUT","0:05")); MouseTimeout = GetSeconds(Buffer); /* Determine whether to enable the keypress * mouse blanker or not. */ String = ArgString(ToolTypes,"KEYBLANK","Yes"); if(!Stricmp(String,"No") || !Stricmp(String,"Off")) KeyBlank = FALSE; else KeyBlank = TRUE; } /* Link the hotkey. */ AttachCxObj(Broker,HotKey(HotkeyBuffer,CxPort,POP_WINDOW)); /* Link another hotkey. */ AttachCxObj(Broker,HotKey(BlankScreenBuffer,CxPort,BLANK_SCREEN)); /* Install the plain InputEvent handler. */ ObjectList = CxCustom(BlankerAction,NULL); /* Any accumulated errors? */ if(!CxObjError(ObjectList)) { /* Add the custom object. */ AttachCxObj(Broker,ObjectList); /* Any errors? */ if(!CxObjError(Broker)) { /* Activate the broker. */ ActivateCxObj(Broker,TRUE); return(TRUE); } } } } ShutdownCx(); return(FALSE); } /* HandleCxMsg(CxMsg *Message): * * Handle incoming Commodities messages. */ VOID __regargs HandleCxMsg(CxMsg *Message) { ULONG MessageID = CxMsgID(Message),MessageType = CxMsgType(Message); ReplyMsg((struct Message *)Message); /* Take a look at the message type. */ switch(MessageType) { /* It's a hotkey. */ case CXM_IEVENT: switch(MessageID) { /* Create the control panel. */ case POP_WINDOW: SetupWindow(); break; /* Blank the screen. */ case BLANK_SCREEN: if(!BlankTask) Signal(BlankerControlTask,SIG_START); else { Signal(BlankerControlTask,SIG_CHANGE); PatternCount = 0; } break; } break; /* It's an internal Commodities command. */ case CXM_COMMAND: switch(MessageID) { /* Disable the Commodity. */ case CXCMD_DISABLE: ActivateCxObj(Broker,FALSE); break; /* Enable the Commodity. */ case CXCMD_ENABLE: ActivateCxObj(Broker,TRUE); break; /* Create the control panel. */ case CXCMD_APPEAR: case CXCMD_UNIQUE: SetupWindow(); break; /* Close the control panel. */ case CXCMD_DISAPPEAR: ShutdownWindow(); break; /* Remove this Commodity. */ case CXCMD_KILL: CloseAll(RETURN_OK); break; } break; } } /* ShowTime(struct Gadget *SomeGadget,WORD Level): * * Gadtools support routine, displays the timeouts. */ LONG __saveds __stdargs ShowTime(struct Gadget *SomeGadget,WORD Level) { STATIC UBYTE Buffer[30]; if(Level) SPrintf(Buffer,"%2ld.%02ld",Level / 60,Level % 60); else SPrintf(Buffer,"-Off-"); return((LONG)Buffer); } /* CreateAllGadgets(): * * Gadtools support routine, creates all the gadgets * required by the control panel. */ struct Gadget * CreateAllGadgets(struct Gadget **GadgetArray,struct Gadget **GadgetList,APTR VisualInfo,UWORD TopEdge) { struct Gadget *Gadget; struct NewGadget NewGadget; UWORD Counter = 0; WindowWidth = 42 * DefaultFontWidth + 20; WindowHeight = TopEdge + 10 + 9 * (DefaultFont . ta_YSize + 6 + INTERHEIGHT) + 4; if(Gadget = CreateContext(GadgetList)) { NewGadget . ng_Width = DefaultFontWidth * 20; NewGadget . ng_Height = DefaultFont . ta_YSize + 6; NewGadget . ng_GadgetText = "_Screen Timeout "; NewGadget . ng_TextAttr = &DefaultFont; NewGadget . ng_VisualInfo = VisualInfo; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_LeftEdge = DefaultFontWidth * 22 + 10; NewGadget . ng_TopEdge = TopEdge + 6; GadgetArray[Counter++] = Gadget = CreateGadget(SLIDER_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 30 * 60, GTSL_Level, ScreenTimeout, GTSL_DispFunc, ShowTime, GTSL_LevelFormat, "%s", GTSL_MaxLevelLen, 5, TAG_DONE); NewGadget . ng_GadgetText = "_Mouse Timeout "; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(SLIDER_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 30 * 60, GTSL_Level, MouseTimeout, GTSL_DispFunc, ShowTime, GTSL_LevelFormat, "%s", GTSL_MaxLevelLen, 5, TAG_DONE); NewGadget . ng_GadgetText = "_Pattern Change "; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(SLIDER_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTSL_Min, 0, GTSL_Max, 30 * 60, GTSL_Level, PatternTimeout, GTSL_DispFunc, ShowTime, GTSL_LevelFormat, "%s", GTSL_MaxLevelLen, 5, TAG_DONE); NewGadget . ng_GadgetText = "Hot _Key"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTST_MaxChars, 255, GTST_String, HotkeyBuffer, TAG_DONE); NewGadget . ng_GadgetText = "_Blank Screen"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTST_MaxChars, 255, GTST_String, BlankScreenBuffer, TAG_DONE); NewGadget . ng_GadgetText = "Ke_ypress blanks mouse"; NewGadget . ng_Width = 26; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCB_Checked, KeyBlank, TAG_DONE); NewGadget . ng_GadgetText = "_Fractal Type"; NewGadget . ng_Width = DefaultFontWidth * 20; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(CYCLE_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCY_Labels, FractalModes, GTCY_Active, FractalType, TAG_DONE); NewGadget . ng_GadgetText = "_Colour Mode"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(CYCLE_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCY_Labels, ColourModes, GTCY_Active, ColourMode, TAG_DONE); NewGadget . ng_GadgetText = "_Hide"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_LeftEdge = 10; NewGadget . ng_TopEdge += NewGadget . ng_Height + 4 + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget, GT_Underscore, '_', TAG_DONE); NewGadget . ng_GadgetText = "_Quit"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_LeftEdge = WindowWidth - 10 - NewGadget . ng_Width; GadgetArray[Counter] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget, GT_Underscore, '_', TAG_DONE); } return(Gadget); } /* ShutdownWindow(): * * Closes the control panel. */ VOID ShutdownWindow() { if(Window) { CloseWindow(Window); ZoomData . Left = -1; Window = NULL; } if(GadgetList) { FreeGadgets(GadgetList); GadgetList = NULL; } if(VisualInfo) { FreeVisualInfo(VisualInfo); VisualInfo = NULL; } if(DefaultScreen) { UnlockPubScreen(NULL,DefaultScreen); DefaultScreen = NULL; } if(LocalFont) { CloseFont(LocalFont); LocalFont = NULL; } } /* CentreWindow(): * * Adjust left/top coordinates of window to be opened to * become visible right below the mouse pointer. */ VOID __regargs CentreWindow(struct Screen *Screen,WORD *LeftEdge,WORD *TopEdge) { (*LeftEdge) = Screen -> MouseX - (WindowWidth >> 1); (*TopEdge) = Screen -> MouseY - (WindowHeight >> 1); while((*LeftEdge) + WindowWidth > Screen -> Width) (*LeftEdge)--; while((*LeftEdge) < 0) (*LeftEdge)++; while((*TopEdge) + WindowHeight > Screen -> Height) (*TopEdge)--; while((*TopEdge) < 0) (*TopEdge)++; } /* SetupWindow(): * * Creates the control panel and disables the screen * blanker. */ BYTE SetupWindow() { if(BlankTask) { struct Task *Task = BlankTask; BlankTask = NULL; RemTask(Task); } if(BlankScreen) { struct Screen *Screen = BlankScreen; BlankScreen = NULL; ScreenToBack(Screen); FreeVPortCopLists(&Screen -> ViewPort); RethinkDisplay(); CloseScreen(Screen); } if(Window) { struct Window *ActiveWindow; struct Screen *FirstScreen; ULONG IntuiLock; BYTE ZipIt; IntuiLock = LockIBase(NULL); FirstScreen = IntuitionBase -> FirstScreen; ActiveWindow = IntuitionBase -> ActiveWindow; UnlockIBase(IntuiLock); if(Window -> WScreen -> TopEdge > 0) { MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge); ZipIt = FALSE; } else ZipIt = TRUE; if(FirstScreen != Window -> WScreen) { ScreenToFront(Window -> WScreen); ZipIt = FALSE; } else ZipIt = TRUE; if(ActiveWindow != Window) { ActivateWindow(Window); ZipIt = FALSE; } else ZipIt = TRUE; if(Window -> Height != WindowHeight) ZipIt = TRUE; WindowToFront(Window); if(ZipIt) ZipWindow(Window); return(TRUE); } else { Forbid(); strcpy(DefaultFontName,GfxBase -> DefaultFont -> tf_Message . mn_Node . ln_Name); DefaultFont . ta_Name = DefaultFontName; DefaultFont . ta_YSize = GfxBase -> DefaultFont -> tf_YSize; DefaultFont . ta_Style = GfxBase -> DefaultFont -> tf_Style; DefaultFont . ta_Flags = GfxBase -> DefaultFont -> tf_Flags & ~FPF_REMOVED; DefaultFontWidth = GfxBase -> DefaultFont -> tf_XSize; Permit(); if(LocalFont = (struct TextFont *)OpenFont(&DefaultFont)) { if(DefaultScreen = (struct Screen *)LockPubScreen(NULL)) { if(VisualInfo = GetVisualInfo(DefaultScreen,TAG_DONE)) { if(CreateAllGadgets(&GadgetArray[0],&GadgetList,VisualInfo,DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1)) { WORD Left,Top; CentreWindow(DefaultScreen,&Left,&Top); if(ZoomData . Left == -1) { ZoomData . Left = 0; ZoomData . Top = 0; ZoomData . Width = WindowWidth >> 1; ZoomData . Height = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1; } if(Window = OpenWindowTags(NULL, WA_CustomScreen, DefaultScreen, WA_Left, Left, WA_Top, Top, WA_Width, WindowWidth, WA_Height, WindowHeight, WA_Activate, TRUE, WA_DragBar, TRUE, WA_DepthGadget, TRUE, WA_CloseGadget, TRUE, WA_RMBTrap, TRUE, WA_Zoom, &ZoomData, WA_NoCareRefresh, TRUE, WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_REFRESHWINDOW | IDCMP_NEWSIZE | SLIDERIDCMP | BUTTONIDCMP, WA_Title, "Fractal Blanker v2.2", TAG_DONE)) { SetFont(Window -> RPort,LocalFont); AddGList(Window,GadgetList,(UWORD)-1,(UWORD)-1,NULL); RefreshGList(GadgetList,Window,NULL,(UWORD)-1); GT_RefreshWindow(Window,NULL); if(Window -> WScreen -> TopEdge > 0) MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge); ScreenToFront(Window -> WScreen); UnlockPubScreen(NULL,DefaultScreen); DefaultScreen = NULL; return(TRUE); } } } } } ShutdownWindow(); return(FALSE); } } /* CloseAll(LONG ReturnCode): * * Free all resources and exit the program. */ VOID __regargs CloseAll(LONG ReturnCode) { if(CxBase && IconBase) { ShutdownCx(); ArgArrayDone(); } if(MouseBlankerTask) { Signal(MouseBlankerTask,SIG_BREAK); Wait(SIG_WAKEUP); } if(BlankerControlTask) RemTask(BlankerControlTask); if(BlankTask) RemTask(BlankTask); if(BlankScreen) { ScreenToBack(BlankScreen); FreeVPortCopLists(&BlankScreen -> ViewPort); RethinkDisplay(); CloseScreen(BlankScreen); BlankScreen = NULL; } ShutdownWindow(); if(IconBase) CloseLibrary(IconBase); if(UtilityBase) CloseLibrary(UtilityBase); if(CxBase) CloseLibrary(CxBase); if(GadToolsBase) CloseLibrary(GadToolsBase); if(GfxBase) CloseLibrary(GfxBase); if(IntuitionBase) CloseLibrary(IntuitionBase); exit(ReturnCode); } /* OpenAll(int argc,char **argv): * * Open all resources, initialize the colour table and * create the Commodities interface. */ VOID __regargs OpenAll(int argc,char **argv) { UBYTE **ToolTypes,*String; WORD i,c = 0,r = 15,g = 0,b = 0; /* Set up the pointer to our process structure. */ MainProcess = (struct Process *)SysBase -> ThisTask; /* Create a table of rainbow colours. */ for(i = 0 ; i < 16 ; i++) Table[c++] = (r << 8) | ((g++) << 4) | b; g = 15; r--; for(i = 0 ; i < 15 ; i++) Table[c++] = ((r--) << 8) | (g << 4) | b; r = 0; g--; b++; for(i = 0 ; i < 15 ; i++) Table[c++] = (r << 8) | ((g--) << 4) | (b++); g = 0; b = 15; r++; for(i = 0 ; i < 15 ; i++) Table[c++] = ((r++) << 8) | (g << 4) | b; r = 15; b--; for(i = 0 ; i < 14 ; i++) Table[c++] = (r << 8) | (g << 4) | (b--); /* Open the libraries we need. */ if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37))) CloseAll(RETURN_FAIL + 0); if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37))) CloseAll(RETURN_FAIL + 1); if(!(GadToolsBase = OpenLibrary("gadtools.library",37))) CloseAll(RETURN_FAIL + 2); if(!(CxBase = OpenLibrary("commodities.library",37))) CloseAll(RETURN_FAIL + 3); if(!(UtilityBase = OpenLibrary("utility.library",37))) CloseAll(RETURN_FAIL + 4); if(!(IconBase = OpenLibrary("icon.library",37))) CloseAll(RETURN_FAIL + 5); if(!(BlankerControlTask = (struct Task *)CreateTask("FracBlank Control Task",100,BlankerControl,8192))) CloseAll(RETURN_FAIL + 6); if(!(MouseBlankerTask = (struct Task *)CreateTask("FracBlank Mouse Blanker Task",100,MouseBlanker,8192))) CloseAll(RETURN_FAIL + 7); /* Wait for handshake signal. */ Wait(SIG_WAKEUP); /* Is the blanker still running? */ if(!MouseBlankerTask) CloseAll(RETURN_FAIL + 8); /* Parse the startup arguments. */ ToolTypes = ArgArrayInit(argc,argv); /* Provide default values. */ strcpy(HotkeyBuffer, "shift f1"); strcpy(BlankScreenBuffer, "shift f2"); /* Create the commodities interface. */ if(!SetupCx(ToolTypes)) CloseAll(RETURN_FAIL + 9); /* Pop up the control panel if necessary. */ if(ToolTypes) { String = ArgString(ToolTypes,"CX_POPUP","no"); if(!Stricmp(String,"yes")) SetupWindow(); } } /* main(int argc,char **argv): * * That's where all the trouble starts. */ VOID __stdargs main(int argc,char **argv) { ULONG SignalSet; /* Open everything we need. */ OpenAll(argc,argv); /* Go into loop waiting for messages. */ FOREVER { /* Wait for a signal... */ SignalSet = Wait(SIG_CX | SIG_BREAK | SIG_WAKEUP | SIG_WINDOW); /* Check the commodities toolkit reply port. */ if(SignalSet & SIG_CX) { CxMsg *Message; while(Message = (CxMsg *)GetMsg(CxPort)) HandleCxMsg(Message); } /* ^C tells the program to quit. */ if(SignalSet & SIG_BREAK) CloseAll(RETURN_OK); /* ^F tells the program to open its control panel. */ if(SignalSet & SIG_WAKEUP) SetupWindow(); /* If the control panel is still open, * check for new messages. */ if(SignalSet & SIG_WINDOW) { struct IntuiMessage *Massage; struct Gadget *Gadget; ULONG Class,Code; while(Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort)) { Class = Massage -> Class; Code = Massage -> Code; Gadget = (struct Gadget *)Massage -> IAddress; GT_ReplyIMsg(Massage); switch(Class) { /* Close the window. */ case IDCMP_CLOSEWINDOW: ShutdownWindow(); break; /* Gadtools does not seem to handle * it yet: refresh the window * contents. */ case IDCMP_NEWSIZE: GT_RefreshWindow(Window,NULL); break; /* Set the slider values. */ case IDCMP_MOUSEMOVE: switch(Gadget -> GadgetID) { case GAD_SCREENTIMEOUT: ScreenCount = 0; ScreenTimeout = Code; break; case GAD_MOUSETIMEOUT: MouseTimeout = Code; break; case GAD_PATTERNCHANGE: PatternCount = 0; PatternTimeout = Code; break; } break; /* Handle the keyboard shortcuts. */ case IDCMP_VANILLAKEY: switch(Code) { case 's': ScreenCount = 0; if(ScreenTimeout + 1 <= 30 * 60) ScreenTimeout++; GT_SetGadgetAttrs(GadgetArray[GAD_SCREENTIMEOUT],Window,NULL, GTSL_Level,ScreenTimeout, TAG_DONE); break; case 'S': ScreenCount = 0; if(ScreenTimeout > 0) ScreenTimeout--; GT_SetGadgetAttrs(GadgetArray[GAD_SCREENTIMEOUT],Window,NULL, GTSL_Level,ScreenTimeout, TAG_DONE); break; case 'm': if(MouseTimeout + 1 <= 30 * 60) MouseTimeout++; GT_SetGadgetAttrs(GadgetArray[GAD_MOUSETIMEOUT],Window,NULL, GTSL_Level,MouseTimeout, TAG_DONE); break; case 'M': if(MouseTimeout > 0) MouseTimeout--; GT_SetGadgetAttrs(GadgetArray[GAD_MOUSETIMEOUT],Window,NULL, GTSL_Level,MouseTimeout, TAG_DONE); break; case 'p': PatternCount = 0; if(PatternTimeout + 1 <= 30 * 60) PatternTimeout++; GT_SetGadgetAttrs(GadgetArray[GAD_PATTERNCHANGE],Window,NULL, GTSL_Level,PatternTimeout, TAG_DONE); break; case 'P': PatternCount = 0; if(PatternTimeout > 0) PatternTimeout--; GT_SetGadgetAttrs(GadgetArray[GAD_PATTERNCHANGE],Window,NULL, GTSL_Level,PatternTimeout, TAG_DONE); break; case 'k': case 'K': ActivateGadget(GadgetArray[GAD_HOTKEY],Window,NULL); break; case 'b': case 'B': ActivateGadget(GadgetArray[GAD_BLANKSCREEN],Window,NULL); break; case 'y': case 'Y': KeyBlank ^= TRUE; GT_SetGadgetAttrs(GadgetArray[GAD_KEYBLANK],Window,NULL, GTCB_Checked,KeyBlank, TAG_DONE); break; case 'f': FractalType = (FractalType + 1) % 3; GT_SetGadgetAttrs(GadgetArray[GAD_FRACTAL],Window,NULL, GTCY_Active,FractalType, TAG_DONE); break; case 'F': if(FractalType) FractalType--; else FractalType = FRACTAL_RANDOM; GT_SetGadgetAttrs(GadgetArray[GAD_FRACTAL],Window,NULL, GTCY_Active,FractalType, TAG_DONE); break; case 'c': ColourMode = (ColourMode + 1) % 3; GT_SetGadgetAttrs(GadgetArray[GAD_COLOUR],Window,NULL, GTCY_Active,ColourMode, TAG_DONE); break; case 'C': if(ColourMode) ColourMode--; else ColourMode = COLOUR_MONO; GT_SetGadgetAttrs(GadgetArray[GAD_COLOUR],Window,NULL, GTCY_Active,ColourMode, TAG_DONE); break; case '\033': case 'h': case 'H': ShutdownWindow(); break; case 3: case 'q': case 'Q': CloseAll(RETURN_OK); default: break; } break; /* Handle the gadgets themselves. */ case IDCMP_GADGETUP: switch(Gadget -> GadgetID) { case GAD_HOTKEY: strcpy(HotkeyBuffer,GT_STRING(Gadget)); if(!SetupCx(NULL)) CloseAll(RETURN_FAIL + 5); break; case GAD_BLANKSCREEN: strcpy(BlankScreenBuffer,GT_STRING(Gadget)); if(!SetupCx(NULL)) CloseAll(RETURN_FAIL + 5); break; case GAD_KEYBLANK: KeyBlank = GT_CHECKED(Gadget); break; case GAD_FRACTAL: FractalType = Code; break; case GAD_COLOUR: ColourMode = Code; break; case GAD_HIDE: ShutdownWindow(); break; case GAD_QUIT: CloseAll(RETURN_OK); } break; } /* Window has been closed, do not * continue requesting messages * from the UserPort. */ if(!Window) break; } } } }