/* $Revision Header * Header built automatically - do not edit! ************* * * (C) Copyright 1991 by Olaf Barthel & MXM * * Name .....: FracBlank.c * Created ..: Friday 18-Jun-91 15:28 * Revision .: 8 * * Date Author Comment * ========= ======== ==================== * 09-Sep-91 Olsen Numerous bug fixes. * 17-Aug-91 Olsen Rewrote sprite blanker code. * 17-Aug-91 Olsen Added cycle gadget. * 12-Aug-91 Olsen Added multicolour/monochrome mode. * 30-Jun-91 Olsen VBlank code revised. * 29-Jun-91 Olsen Added VBlank interrupt server. * 21-Jun-91 Olsen Optimizations, cleanups. * 18-Jun-91 Olsen Created this file! * * $Revision Header ********************************************************/ /* Include the specific math pragmas/header files here (is there * any way to figure this out by taking a look at 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) /* Hotkey IDs. */ enum { POP_WINDOW,BLANK_SCREEN }; /* Gadget IDs. */ enum { GAD_SCREENTIMEOUT,GAD_PATTERNCHANGE,GAD_HOTKEY, GAD_BLANKSCREEN,GAD_MONO,GAD_CYCLE,GAD_HIDE,GAD_QUIT }; /* Dimensions of the control panel. */ #define WIDTH 284 #define HEIGHT 113 /* Program revision tag. */ STATIC const UBYTE * const VersTag = "\0$VER: FracBlank 1.8 (9.9.91)"; /* Shared library identifiers. */ extern struct ExecBase *SysBase; struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Library *CxBase, *IconBase, *GadToolsBase; /* Blanker data. */ struct Task *BlankTask; struct Screen *BlankScreen; /* Commodities interface data. */ struct MsgPort *CxPort; CxObj *Broker; /* Gfx and gadtools data. */ struct Screen *DefaultScreen; APTR VisualInfo; struct TextFont *Topaz; struct Gadget *GadgetList; struct Gadget *GadgetArray[8]; struct Window *Window; /* Window zoom data. */ WORD ZoomData[4] = { -1,-1,-1,-1 }; /* Rainbow colour table. */ UWORD Table[75]; /* Key sequence buffers. */ UBYTE HotkeyBuffer[256],BlankScreenBuffer[256]; /* Screen and pattern change timeout. */ ULONG ScreenCount = 0,PatternCount = 0,ScreenTimeout = 60,PatternTimeout = 60; /* Display mode: monochrome / multicolor. */ BYTE Mono = FALSE,Cycle = TRUE; /* The default font to be used by the control panel. */ struct TextAttr DefaultFont = { (UBYTE *)"topaz.font", 8, FS_NORMAL, FPF_ROMFONT }; /* A new broker definition, Commodities needs this. */ struct NewBroker NewBroker = { NB_VERSION, "FracBlanker", "Fractal Blanker v1.8", "Screen Blanker", NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE, 0,NULL,0 }; /* 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); VOID StartBlanker(VOID); ULONG __regargs Random(ULONG MaxValue); VOID __saveds Blanker(VOID); VOID __saveds __stdargs BlankerAction(CxMsg *CxMessage,CxObj *CxObject); VOID ShutdownCx(VOID); BYTE __regargs SetupCx(UBYTE **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); /* StartBlanker(): * * Open the display screen and create the blanker task. */ VOID StartBlanker() { if(!BlankScreen) { struct Screen *Screen; if(Screen = OpenScreenTags(NULL, SA_Behind, TRUE, SA_Quiet, TRUE, SA_DisplayID, Mono ? HIRESLACE_KEY : LORES_KEY, SA_Overscan, OSCAN_MAX, SA_Depth, Mono ? 1 : 5, TAG_DONE)) { 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 instruction. */ CINIT(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 background colour to black. */ SetRGB4(&Screen -> ViewPort,0,0x0,0x0,0x0); /* Display the screen. */ ScreenToFront(Screen); BlankScreen = Screen; } else CloseScreen(Screen); } } if(BlankScreen) { PatternCount = 0; BlankTask = (struct Task *)CreateTask("FracBlank.task",-20,Blanker,4000); } } /* 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); } /* Blanker(): * * The screen blanker itself. */ VOID __saveds Blanker() { 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,save; SetSignal(0,SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E); /* Are we running in monochrome mode? */ if(Mono) { UWORD Modulo = BlankScreen -> RastPort . BitMap -> BytesPerRow; PLANEPTR Plane = BlankScreen -> RastPort . BitMap -> Planes[0]; /* Provide starting numbers for the fractal * parameters. */ a = (float)Random(300) / 100; b = (float)Random(100) / 100; c = (float)Random( 50) / 100; mag = (float)(1 << (Random(4) + 5)) * 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 { /* 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((save = b * x - c) < 0) save = -save; if(x < 0) x = y + sqrt(save); else x = y - sqrt(save); 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); /* ^D tells the blanker to change the pattern. */ if(SetSignal(0,0) & SIGBREAKF_CTRL_D) { SetSignal(0,SIGBREAKF_CTRL_D); SetRast(&BlankScreen -> RastPort,0); x = y = 0; a = (float)Random(300) / 100; b = (float)Random(100) / 100; c = (float)Random( 50) / 100; mag = (float)(1 << (Random(4) + 5)) * deg45; } /* ^E tells the blanker to rotate the * colours. */ if(SetSignal(0,0) & SIGBREAKF_CTRL_E) { SetSignal(0,SIGBREAKF_CTRL_E); Colours[1] = Table[Wheel]; LoadRGB4(&BlankScreen -> ViewPort,Colours,2); Wheel = (Wheel + 1) % 75; } } } else { STATIC 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 }; UWORD Count = 0; WORD i; BYTE Colour = 1,Plus = 1; struct RastPort *RPort; a = (float)Random(300) / 100; b = (float)Random(100) / 100; c = (float)Random( 50) / 100; mag = (float)(1 << (Random(4) + 2)) * deg45; Colours[0] = 0x000; for(i = 1 ; i < 32 ; i++) Colours[i] = Table[(Wheel + i) % 75]; if(Cycle) LoadRGB4(&BlankScreen -> ViewPort,Colours,32); else LoadRGB4(&BlankScreen -> ViewPort,Rainbow,32); Wheel = (Wheel + 1) % 75; RPort = &BlankScreen -> RastPort; FOREVER { yy = a - x; if((save = b * x - c) < 0) save = -save; if(x < 0) x = y + sqrt(save); else x = y - sqrt(save); y = yy; sx = mag * ( x + y); sy = mag * (-x + y); MultiPlot(BlankScreen,(WORD)(sx) + OffsetX,(WORD)(sy) + OffsetY,Colour); /* 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 * 900 pixels have been rendered and will * pick a new colour between 1 and 31. */ if(Count++ >= 900) { Count = 0; Colour += Plus; if(!Colour) { Plus = 1; Colour = 2; } else { if(Colour == 32) { Plus = -1; Colour = 30; } } } if(SetSignal(0,0) & SIGBREAKF_CTRL_D) { SetSignal(0,SIGBREAKF_CTRL_D); SetRast(RPort,0); x = y = 0; a = (float)Random(300) / 100; b = (float)Random(100) / 100; c = (float)Random( 50) / 100; mag = (float)(1 << (Random(4) + 2)) * deg45; } if(SetSignal(0,0) & SIGBREAKF_CTRL_E) { SetSignal(0,SIGBREAKF_CTRL_E); for(i = 1 ; i < 32 ; i++) Colours[i] = Table[(Wheel + i) % 75]; if(Cycle) LoadRGB4(&BlankScreen -> ViewPort,Colours,32); Wheel = (Wheel + 1) % 75; } } } /* Quietly remove ourselves. */ Forbid(); BlankTask = NULL; RemTask(SysBase -> ThisTask); } /* 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 = 1; struct InputEvent *Event = (struct InputEvent *)CxMsgData(CxMessage); /* Push the blanker screen to the front if necessary. */ if(BlankScreen) { if(BlankScreen -> TopEdge) MoveScreen(BlankScreen,0,-BlankScreen -> TopEdge); if(IntuitionBase -> FirstScreen != BlankScreen) ScreenToFront(BlankScreen); } /* This looks like a timer event. */ if(Event -> ie_Class == IECLASS_TIMER && !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) { if(!BlankTask) StartBlanker(); } } } else { if(Count < 0) Count = 0; /* Every 5/60 second we signal the blanker * task to rotate the palette. */ if(Count++ >= 2) { Signal(BlankTask,SIGBREAKF_CTRL_E); Count = 0; } /* Is it time to change the pattern? */ if(PatternTimeout) { if(PatternCount++ >= PatternTimeout * 10) { Signal(BlankTask,SIGBREAKF_CTRL_D); PatternCount = 0; } } } } else { /* The following line determines whether * the blanker is to be removed or to * be left running. */ if((Event -> ie_Class == IECLASS_RAWKEY && !(Event -> ie_Code & IECODE_UP_PREFIX) && !(Event -> ie_Qualifier & IEQUALIFIER_REPEAT)) || Event -> ie_Class == IECLASS_RAWMOUSE) { /* Remove the blanker task. */ if(BlankTask) { struct Task *Task = BlankTask; BlankTask = NULL; RemTask(Task); } /* Close the blanker screen. */ if(BlankScreen) { struct Screen *Screen = BlankScreen; BlankScreen = NULL; ScreenToBack(Screen); FreeVPortCopLists(&Screen -> ViewPort); RemakeDisplay(); CloseScreen(Screen); } } 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(UBYTE *String): * * Calculates the number of seconds corresponding to * expressions such as `11:25' or `10'. */ WORD GetSeconds(UBYTE *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(UBYTE **ToolTypes): * * Set up the Commodities interface. */ BYTE __regargs SetupCx(UBYTE **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); /* Cycle the multicolour palette? */ String = ArgString(ToolTypes,"CYCLE","yes"); if(!strcmpi(String,"yes")) Cycle = TRUE; else Cycle = FALSE; /* Run in monochrome mode? */ String = ArgString(ToolTypes,"MONO","no"); if(!strcmpi(String,"yes")) Mono = TRUE; else Mono = FALSE; /* 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); } /* 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) StartBlanker(); else { /* Tell the blanker task to change the pattern. */ Signal(BlankTask,SIGBREAKF_CTRL_D); 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; if(Gadget = CreateContext(GadgetList)) { NewGadget . ng_Width = 104; NewGadget . ng_Height = 12; NewGadget . ng_GadgetText = "_Screen Timeout "; NewGadget . ng_TextAttr = &DefaultFont; NewGadget . ng_VisualInfo = VisualInfo; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_LeftEdge = (strlen(NewGadget . ng_GadgetText) + 2 - 1) * 8 - 2; NewGadget . ng_TopEdge = 1 + TopEdge; 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 = "_Pattern Change "; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + 1; 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 + 2; NewGadget . ng_Height = 14; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTST_MaxChars, 256, GTST_String, HotkeyBuffer, TAG_DONE); NewGadget . ng_GadgetText = "_Blank Screen"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + 1; NewGadget . ng_Height = 14; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTST_MaxChars, 256, GTST_String, BlankScreenBuffer, TAG_DONE); NewGadget . ng_GadgetText = "_Monochrome"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + 2; NewGadget . ng_Height = 12; GadgetArray[Counter++] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCB_Checked, Mono, TAG_DONE); NewGadget . ng_GadgetText = "_Cycle"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge += NewGadget . ng_Height + 1; GadgetArray[Counter++] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCB_Checked, Cycle, TAG_DONE); NewGadget . ng_GadgetText = "_Hide"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_LeftEdge = 6; NewGadget . ng_TopEdge = HEIGHT - 3 - NewGadget . ng_Height; GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget, GT_Underscore, '_', TAG_DONE); NewGadget . ng_GadgetText = "_Quit"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_LeftEdge = WIDTH - 6 - 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); Window = NULL; } if(GadgetList) { FreeGadgets(GadgetList); GadgetList = NULL; } if(VisualInfo) { FreeVisualInfo(VisualInfo); VisualInfo = NULL; } if(DefaultScreen) { UnlockPubScreen(NULL,DefaultScreen); DefaultScreen = NULL; } if(Topaz) { CloseFont(Topaz); Topaz = 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 - (WIDTH >> 1); (*TopEdge) = Screen -> MouseY - (HEIGHT >> 1); while((*LeftEdge) + WIDTH > Screen -> Width) (*LeftEdge)--; while((*LeftEdge) < 0) (*LeftEdge)++; while((*TopEdge) + HEIGHT > 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); RemakeDisplay(); CloseScreen(Screen); } if(Window) return(TRUE); if(Topaz = (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[0] == -1) { ZoomData[0] = 0; ZoomData[1] = 0; ZoomData[2] = WIDTH; ZoomData[3] = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1; } if(Window = OpenWindowTags(NULL, WA_Left, Left, WA_Top, Top, WA_Width, WIDTH, WA_Height, HEIGHT + DefaultScreen -> Font -> ta_YSize - 8, WA_Activate, TRUE, WA_DragBar, TRUE, WA_DepthGadget, TRUE, WA_CloseGadget, TRUE, WA_RMBTrap, TRUE, WA_Zoom, ZoomData, WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_NEWSIZE | SLIDERIDCMP | BUTTONIDCMP, WA_Title, "Fractal Blanker v1.8", TAG_DONE)) { SetFont(Window -> RPort,Topaz); AddGList(Window,GadgetList,(UWORD)-1,(UWORD)-1,NULL); RefreshGList(GadgetList,Window,NULL,(UWORD)-1); GT_RefreshWindow(Window,NULL); 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(BlankTask) RemTask(BlankTask); if(BlankScreen) { ScreenToBack(BlankScreen); FreeVPortCopLists(&BlankScreen -> ViewPort); RemakeDisplay(); CloseScreen(BlankScreen); BlankScreen = NULL; } ShutdownWindow(); if(IconBase) CloseLibrary(IconBase); 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; /* 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(!(IconBase = OpenLibrary("icon.library",37))) CloseAll(RETURN_FAIL + 4); /* 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 + 5); /* Pop up the control panel if necessary. */ if(ToolTypes) { String = ArgString(ToolTypes,"CX_POPUP","no"); if(!strcmpi(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 { SignalSet = (1 << CxPort -> mp_SigBit) | SIGBREAKF_CTRL_C; /* If the window is still open, wait for * some news. */ if(Window) SignalSet |= (1 << Window -> UserPort -> mp_SigBit); SignalSet = Wait(SignalSet); /* There are messages pending at the * Commodities reply port. */ if(SignalSet & (1 << CxPort -> mp_SigBit)) { CxMsg *Message; while(Message = (CxMsg *)GetMsg(CxPort)) HandleCxMsg(Message); } /* ^E tells the program to quit. */ if(SignalSet & SIGBREAKF_CTRL_C) CloseAll(RETURN_OK); /* If the control panel is still open, * check for new messages. */ if(Window) { if(SignalSet & (1 << Window -> UserPort -> mp_SigBit)) { 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; 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_PATTERNCHANGE: PatternCount = 0; PatternTimeout = Code; break; } break; /* Handle the keyboard shortcuts. */ case IDCMP_VANILLAKEY: switch(toupper(Code)) { case 'S': ScreenCount = 0; if(Code == 's') { if(ScreenTimeout + 1 <= 30 * 60) ScreenTimeout++; else ScreenTimeout = ScreenTimeout + 1 - 30 * 60; } else { if(ScreenTimeout > 0) ScreenTimeout--; else ScreenTimeout = 30 * 60; } GT_SetGadgetAttrs(GadgetArray[GAD_SCREENTIMEOUT],Window,NULL, GTSL_Level,ScreenTimeout, TAG_DONE); break; case 'P': PatternCount = 0; if(Code == 'p') { if(PatternTimeout + 1 <= 30 * 60) PatternTimeout++; else PatternTimeout = PatternTimeout + 1 - 30 * 60; } else { if(PatternTimeout > 0) PatternTimeout--; else PatternTimeout = 30 * 60; } GT_SetGadgetAttrs(GadgetArray[GAD_PATTERNCHANGE],Window,NULL, GTSL_Level,PatternTimeout, TAG_DONE); break; case 'K': ActivateGadget(GadgetArray[GAD_HOTKEY],Window,NULL); break; case 'B': ActivateGadget(GadgetArray[GAD_BLANKSCREEN],Window,NULL); break; case 'M': Mono ^= TRUE; GT_SetGadgetAttrs(GadgetArray[GAD_MONO],Window,NULL, GTCB_Checked,Mono, TAG_DONE); break; case 'C': Cycle ^= TRUE; GT_SetGadgetAttrs(GadgetArray[GAD_CYCLE],Window,NULL, GTCB_Checked,Cycle, TAG_DONE); break; case 'H': ShutdownWindow(); break; case 'Q': CloseAll(RETURN_OK); default: break; } break; /* Handle the gadgets themselves. */ case IDCMP_GADGETUP: switch(Gadget -> GadgetID) { case GAD_HOTKEY: strcpy(HotkeyBuffer,((struct StringInfo *)Gadget -> SpecialInfo) -> Buffer); if(!SetupCx(NULL)) CloseAll(RETURN_FAIL + 5); break; case GAD_BLANKSCREEN: strcpy(BlankScreenBuffer,((struct StringInfo *)Gadget -> SpecialInfo) -> Buffer); if(!SetupCx(NULL)) CloseAll(RETURN_FAIL + 5); break; case GAD_MONO: if(Gadget -> Flags & GFLG_SELECTED) Mono = TRUE; else Mono = FALSE; break; case GAD_CYCLE: if(Gadget -> Flags & GFLG_SELECTED) Cycle = TRUE; else Cycle = FALSE; 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; } } } } }