/* MouseClock.c ************************************************************* * * MouseClock ---- Ein Uhren-Utility, das ausnahmsweise nicht * irgendwo auf einem obskuren Bildschirm * (meinetwegen auch Workbench-Bildschirm) * existiert, sondern sich in der Nähe des * Mauszeigers aufhält. Die Position und * der Bildschirm, auf dem sich die Anzeige * von MouseClock aufhält, ist unabhängig vom * Workbench-Bildschirm. Ähnlich wie beim * Mauszeiger liegen die Sprites, die Mouseclock * zur Anzeige verwendet, immer auf dem vordersten * Bildschirm. * * Besonders stolz (soviel Eitelkeit darf ich * mir hoffentlich gönnen) bin ich auf den Interrupt- * code, der die Anzeige bewegt. Es hat auf * Anhieb geklappt und ist noch nicht ein einziges * mal abgeschmiert. * * Autor --------- Olaf Barthel, ED Electronic Design Hannover * Brabeckstraße 35 * D-3000 Hannover 71 * * Bundesrepublik Deutschland * * (C) Copyright 1989 by Olaf Barthel & * ED Electronic Design Hannover * ****************************************************************************/ #include #include #include #include #include #include #include /* Vorwärtsdeklarationen, um Compiler-Warnungen zu * zu vermeiden. */ extern struct Library *OpenLibrary(); extern struct Window *OpenWindow(); extern struct ViewPort *ViewPortAddress(); extern struct Message *GetMsg(); extern struct MsgPort *CreatePort(); extern struct MsgPort *FindPort(); extern void *AllocMem(); extern PLANEPTR AllocRaster(); extern long AvailMem(); /* Globale Variablen, die zur Handhabung des Displays * und des Fensters dienen. */ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Window *Window; struct IntuiMessage *Massage; struct MsgPort *MouseClockPort; /* Wir orientieren uns zwar nicht am vordersten ViewPort, * wenn wir die Sprites setzen, passen aber die Farben * der Sprites an, wenn ein Bildschirm weniger als 32 * Farben hat. */ struct ViewPort *VPort; /* Die beiden Sprites der Anzeige. */ struct SimpleSprite Position1,Position2; /* Mit diesen Variablen wird später Schrift in die Sprites * gedruckt. */ struct BitMap PointerBMap; struct RastPort PointerRPort; /* Aktuelle Position des Mauszeigers, soll die Interruptroutine * den Mauszeiger bearbeiten? */ WORD CurX,CurY,DoPosition = FALSE; /* Datenspeicher für die Spritedaten. */ UWORD Pointer1Data[(2 + 72) * 2],Pointer2Data[(2 + 72) * 2]; /* Zeichenfarben für Schrift und Hintergrund. */ UBYTE Render[3],Shadow[3]; /* Mit den folgenden Daten werden Fonts zum Zeichnen der * Kurzinfo definiert. */ struct TextAttr AboutFont[3] = { {(UBYTE *)"topaz.font",8,FS_NORMAL ,FPF_ROMFONT}, {(UBYTE *)"topaz.font",8,FSF_BOLD ,FPF_ROMFONT}, {(UBYTE *)"topaz.font",8,FSF_ITALIC,FPF_ROMFONT} }; /* Dies ist die "Kurzinfo", die gezeigt wird, wenn unser * Fenster aktiviert worden ist. Der Titlebar des * Workbench-Bildschirms wird ein wenig verschönert. */ struct IntuiText AboutTxt[4] = { {3,1,JAM1, 0,1,(struct TextAttr *)&AboutFont[1],(UBYTE *)"MouseClock", (struct IntuiText *)&AboutTxt[ 1]}, {2,1,JAM1, 88,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"v1.2", (struct IntuiText *)&AboutTxt[ 2]}, {2,1,JAM1,128,1,(struct TextAttr *)&AboutFont[0],(UBYTE *)"© 1989 by", (struct IntuiText *)&AboutTxt[ 3]}, {0,1,JAM1,232,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"Electronic Design Hannover", (struct IntuiText *)NULL} }; /* Bitmapdaten um das ED-Symbol über dem Schließgadget * zeichnen zu können. */ USHORT ClipMap[40] = { 0xFFFF,0xF000,0xFFFF,0xF000,0xF001,0xF000,0xF7FF,0xF000, 0xFFFF,0xD000,0xF03F,0xD000,0xF7FF,0x9000,0xFFFF,0x3000, 0xF000,0x7000,0xFFFF,0xF000, 0x0000,0x0000,0x1FFF,0x0000,0x3FFF,0x8000,0x3800,0xC000, 0x1F80,0xE000,0x3FC0,0xE000,0x3801,0xE000,0x1FFF,0xC000, 0x0FFF,0x8000,0x0000,0x0000 }; /* Zum Einzeichnen des ED-Symbols notwendige Definition. */ struct Image ClipImage = { 0,0, 20,10,2, (USHORT *)ClipMap, 0x03,0x00, (struct Image *)NULL }; /* Dieses Fenster wird geöffnet, um u.A. festellen zu * können, ob der Anwender das Programm beenden möchte, * oder sich die Farbe des Mauszeigers geändert hat. */ struct NewWindow NewWindow = { 561,0, 26,10, 1,1, CLOSEWINDOW | NEWPREFS | REFRESHWINDOW | ACTIVEWINDOW, RMBTRAP | WINDOWCLOSE | SIMPLE_REFRESH, (struct Gadget *)NULL, (struct Image *)NULL, (STRPTR)NULL, (struct Screen *)NULL, (struct BitMap *)NULL, 0,0, 0,0, WBENCHSCREEN }; /* Falls sich DMouse irgendwo im Speicher versteckt, borgen * wir den DMouse Mousetimeout, um die Sprites rechtzeitig * verschwinden zu lassen. */ struct DMSFragment { struct MsgPort Port; /* Globaler Messageport. */ short Version;/* Aktuelle Version. */ short Acc; /* Beschleunigung. */ short AThresh;/* Beschleunigungsschwelle. */ long STo; /* Screentimeout. */ long MTo; /* Mousetimeout. */ }; /* Diese Variablen sind notwendig, wenn man sich vom * CLI abkoppeln möchte, von dem man gestartet wird. */ long _stack = 4000; long _priority = 1; long _BackGroundIO = NULL; char *_procname = "MouseClock v1.2"; /* Hilfsstrukturen zur Kontrolle des timer.device. */ struct timerequest *tr_TimerRequest= NULL; struct MsgPort *tr_TimerPort = NULL; /* Mit dieser Struktur wird die Routine zum Positionieren * der Anzeige in den Vertical Blanking Interrupt gehängt. */ struct Interrupt VBlankServer; /* Da wir diese Symbole noch brauchen, um in einigen * Assemblerroutinen herumzukleistern, aber die Assembler- * routinen, die gleich folgen werden, diese Symbole für * den Compiler nicht sichtbar erzeugen, schustern wir * ein wenig herum. */ extern void NuCloseScreen(); extern void HandleVBlank(); /* Hier wird später einmal ein Zeiger auf eine System- * routine erscheinen, OpenScreen() um genau zu sein. * Dieser Wert wird von SetFunction() zurückgeliefert, * wenn wir in den Libraries herumstochern. */ long OldCloseScreen; #asm _HandleVBlank: MOVEM.L A2-A6/D2-D7,-(A7) ; Ein paar Register retten JSR _geta4# ; Adressregister geraderücken JSR _MyHandleVBlank ; C-Routine anspringen CLR.L D0 ; Da wir im Interrupt sind, ; muß D0 gelöscht werden. MOVEM.L (A7)+,A2-A6/D2-D7 ; Die Register restaurieren RTS ; ...und weiter. _NuCloseScreen: MOVEM.L D2/D3/A4/A6,-(SP) ; Ein paar Register retten MOVE.L A0,-(SP) ; Screen-Zeiger als Argument ; übernehmen JSR _geta4# ; Adressregister geraderücken JSR _ModifiedCloseScreen ; C-Routine anspringen ADDQ.L #4,SP ; Stack korrigieren MOVE.L D0,A0 ; Screen weiterleiten MOVE.L _OldCloseScreen,A1 ; Alte Routine merken MOVEM.L (SP)+,D2/D3/A4/A6 ; Register restaurieren JMP (A1) ; Alte Routine anspringen #endasm /* ModifiedCloseScreen(Screen) : * * Ein Patch für die CloseScreen() Routine, damit * sich die Interrupt-Routine nicht an Bildschirme * heranmacht, die gerade geschlossen werden. */ struct Screen * ModifiedCloseScreen(Screen) struct Screen *Screen; { /* Bildschirm nach hinten legen. */ ScreenToBack(Screen); /* Zweimal auf den Durchlauf des Vertical Blanking * warten, damit der Handler auch wirklich mitkriegt, * daß er einen Bildschirm nicht manipulieren kann, * den es in Zehntelsekunden nicht mehr geben wird. * Gut, das ist die kompliziertere Methode, aber * wenigstens geht sie nicht immer in die Hose, * was ohne diesen Patch sehr häufig passiert. */ WaitTOF(); WaitTOF(); /* Man kann ja nicht immer alles auf dem Stack * herumliegen lassen, also liefern wir den Zeiger * zurück, damit die alte CloseScreen() Routine * nicht im Regen steht. */ return(Screen); } /* MyHandleVBlank() : * * Dies ist eine echte Interrupt-Routine in C, * ja das gibt es wirklich und es funktioniert * sogar. In dieser Routine werden die Sprites * bewegt und die Farben gesetzt. Auf diese * Weise ist es wesentlich schneller als eine * multitaskingfähige Unterroutine, die z.B. * auf das timer.device wartet. */ void MyHandleVBlank() { /* WER konnte es ahnen, daß Intuition diese * Daten auf einen Bildschirm bezieht, der * 640 Pixel in X-Richtung und 512 in Y-Richtung * besitzt? Es hat mich eine Menge Zeit gekostet, * herauszufinden, weshalb sich die Anzeige * schneller bewegte als der Mauszeiger selbst, * bis ich herausbekam, daß diese Daten * nicht für Sprites gedacht sind, die sich nur * in Lo-res Schritten bewegen können. */ CurX = IntuitionBase -> MouseX >> 1; CurY = IntuitionBase -> MouseY >> 1; /* Falls nötig, werden die Farben der Sprites * an den aktuellen Bildschirm angepaßt. */ VPort = &IntuitionBase -> FirstScreen -> ViewPort; /* Na woher wissen wir denn, wie tief der Bildschirm * ist? Na, wozu hängt eine RasInfo am ViewPort? */ if(VPort -> RasInfo -> BitMap -> Depth < 5) { SetRGB4(VPort,22,Shadow[0],Shadow[1],Shadow[2]); SetRGB4(VPort,21,Render[0],Render[1],Render[2]); } if(DoPosition) { /* Sprites an die Position rechts neben dem * Mauszeiger rücken. */ MoveSprite(NULL,&Position1,CurX + 8,CurY); MoveSprite(NULL,&Position2,CurX + 24,CurY); } } /* AddVBlankServer() : * * Dies initialisiert eine Struktur, mit deren Hilfe * ein Interruptserver in den Vertical Blanking * Interrupt eingeklinkt wird. */ void AddVBlankServer() { VBlankServer . is_Data = (APTR)NULL; VBlankServer . is_Code = HandleVBlank; VBlankServer . is_Node . ln_Succ= NULL; VBlankServer . is_Node . ln_Pred= NULL; VBlankServer . is_Node . ln_Type= NT_INTERRUPT; VBlankServer . is_Node . ln_Pri = 0; VBlankServer . is_Node . ln_Name= "MouseClock"; /* Herzlichen Dank an Dan Silva, er benutzt eine * ähnliche Methode, um DPaint Colourcycling * beizubringen. Ich hab's einfach einmal * ausprobiert und es lief sofort! */ AddIntServer(5,&VBlankServer); } /* RemVBlankServer() : * * Wirft den Interruptserver wieder aus der Liste * der Interrupts. */ void RemVBlankServer() { /* Hoffentlich baut Exec keinen Mist und * schickt den Server wirklich in die Wüste. */ RemIntServer(5,&VBlankServer); } /* OpenTimerDevice() : * * Öffnet das timer.device für unsere Zwecke. */ BOOL OpenTimerDevice() { if(!(tr_TimerPort = (struct MsgPort *)CreatePort(NULL,0))) return(FALSE); if(!(tr_TimerRequest = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC | MEMF_CLEAR))) { DeletePort(tr_TimerPort); return(FALSE); } /* Präzisionszeitgeber aktivieren. */ if(OpenDevice(TIMERNAME,UNIT_VBLANK,tr_TimerRequest,0)) { FreeMem(tr_TimerRequest,(long)sizeof(struct timerequest)); DeletePort(tr_TimerPort); return(FALSE); } tr_TimerRequest -> tr_node . io_Message . mn_ReplyPort = tr_TimerPort; tr_TimerRequest -> tr_node . io_Command = TR_ADDREQUEST; tr_TimerRequest -> tr_node . io_Flags = 0; tr_TimerRequest -> tr_node . io_Error = 0; return(TRUE); } /* CloseTimerDevice() : * * Gibt den angeforderten Speicher frei und schließt das * timer.device. */ void CloseTimerDevice() { if(tr_TimerRequest) { CloseDevice(tr_TimerRequest); FreeMem(tr_TimerRequest,sizeof(struct timerequest)); } if(tr_TimerPort) DeletePort(tr_TimerPort); } /* WaitTime(Seconds,Micros) : * * Wartet eine Zeitperiode. */ void WaitTime(Seconds,Micros) register ULONG Seconds,Micros; { tr_TimerRequest -> tr_time . tv_secs = Seconds; tr_TimerRequest -> tr_time . tv_micro = Micros; DoIO(tr_TimerRequest); } /* OpenPixel6Font() : * * Aktiviert einen speziellen, 4 Pixel breiten und * 6 Zeilen hohen Zeichensatz, mit dem später in die * Sprites gezeichnet wird. */ struct TextFont * OpenPixel6Font() { static struct TextFont Pixel6Font; static long Pixel6Dump[138] = { 0x04AA2240,0x00002E2E,0xEAEEEEE0,0x0204E4C4, 0xCEE6AE2A,0x8AA4C4C6,0xEAAAAAE6,0x864004A2, 0x242A4000,0x2A222A88,0x2AA444E2,0x2AAAA888, 0xA42A8ECA,0xAAA84AAA,0xAA2482A0,0x04044424, 0xE0E04A2E,0xEEEE2EE0,0x08016EC8,0xAEEAE42C, 0x8EEACAC4,0x4AAE4444,0x42000008,0x042A4400, 0x8A28222A,0x2A2444E2,0x0AAAA88A,0xA4AA8A6A, 0x8AA24AAE,0xA4842200,0x040A0240,0x04048E2E, 0xE2EE2EE0,0x42044AC4,0xCE86AE4A,0xEAA487AC, 0x464AA4E6,0x26000000,0x00000800,0x00000000, 0x00008000,0x00000000,0x00000000,0x00000000, 0x0000000F,0x00000004,0x00040004,0x00080004, 0x00000004,0x00000004,0x000C0004,0x00000004, 0x00100004,0x00140004,0x00180004,0x001C0004, 0x00200004,0x00240004,0x00280004,0x002C0004, 0x00300004,0x00340004,0x00380004,0x003C0004, 0x00400004,0x00440004,0x00480004,0x004C0004, 0x00500004,0x00540004,0x00580004,0x005C0004, 0x00600004,0x00640004,0x00680004,0x006C0004, 0x00700004,0x00000004,0x00740004,0x00780004, 0x007C0004,0x00800004,0x00840004,0x00880004, 0x008C0004,0x00900004,0x00940004,0x00980004, 0x009C0004,0x00A00004,0x00A40004,0x00A80004, 0x00AC0004,0x00B00004,0x00B40004,0x00B80004, 0x00BC0004,0x00C00004,0x00C40004,0x00C80004, 0x00CC0004,0x00D00004,0x00D40004,0x00D80004, 0x00DC0004,0x00E00004,0x00E40004,0x00E80004, 0x00EC0004,0x00540004,0x005400C3,0x66E00000, 0x04002C30,0x78303035,0x43303030,0x342C0A09, 0x09307830,0x30363030,0x3030342C,0x30783030, 0x36343030,0x30342C30,0x78303036,0x38303030, 0x342C3078,0x30303643,0x30303034,0x2C0A0909, 0x30783030,0x37303030,0x30342C30,0x78303030, 0x30303030,0x342C3078,0x30303734,0x30303034, 0x2C307830,0x30373830 }; Pixel6Font . tf_Message . mn_Node . ln_Name = "Pixel.font"; Pixel6Font . tf_Message . mn_Node . ln_Type = NT_FONT; Pixel6Font . tf_Message . mn_Node . ln_Pri = 0; Pixel6Font . tf_YSize = 6; Pixel6Font . tf_Style = 0; Pixel6Font . tf_Flags = 66; Pixel6Font . tf_XSize = 4; Pixel6Font . tf_Baseline = 4; Pixel6Font . tf_BoldSmear = 1; Pixel6Font . tf_Accessors = 0; Pixel6Font . tf_LoChar = 32; Pixel6Font . tf_HiChar = 95; Pixel6Font . tf_CharData = (APTR)&Pixel6Dump[0]; Pixel6Font . tf_Modulo = 30; Pixel6Font . tf_CharLoc = (APTR)((char *)&Pixel6Dump[0] + (0xC4EE3A - 0xC4ED86)); Pixel6Font . tf_CharSpace = 0; Pixel6Font . tf_CharKern = 0; return(&Pixel6Font); } /* CloseAll(ReturnCode) : * * Gibt allen angeforderten Speicher frei, schließt * Libraries, Devices, Fenster, etc. und verläßt das * Programm. */ void CloseAll(ReturnCode) long ReturnCode; { register short i; DoPosition = FALSE; /* Die beiden Sprites brauchen wir nicht mehr. Deshalb * ab in die Wüste damit. */ FreeSprite(2); FreeSprite(3); if(Window) { while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort)) ReplyMsg(Massage); CloseWindow(Window); } /* Bitmapdaten freigeben. */ for(i = 0 ; i < 2 ; i++) if(PointerBMap . Planes[i]) FreeRaster(PointerBMap . Planes[i],16,72); if(IntuitionBase) { /* Intuition wieder Kontrolle über die * eigenen Routinen geben. */ Forbid(); SetFunction(IntuitionBase,-0x42,OldCloseScreen); Permit(); CloseLibrary(IntuitionBase); } if(GfxBase) CloseLibrary(GfxBase); CloseTimerDevice(); /* Den MessagePort, mit dem wir erreichbar waren, * schließen. */ if(MouseClockPort) DeletePort(MouseClockPort); RemVBlankServer(); exit(ReturnCode); } /* OpenAll() : * * Öffnet alles, was geöffnet werden muß und * bereitet Speicher vor, den wir später brauchen * werden. */ void OpenAll() { register short i; if(!(MouseClockPort = (struct MsgPort *)CreatePort("MouseClockPort",0))) CloseAll(20); if(!OpenTimerDevice()) CloseAll(20); if(!(IntuitionBase = (VOID *)OpenLibrary("intuition.library",LIBRARY_VERSION))) CloseAll(20); /* Jetzt hängen wir unsere eigene CloseScreen() * Routine ins System. */ Forbid(); OldCloseScreen = SetFunction(IntuitionBase,-0x42,NuCloseScreen); Permit(); if(!(GfxBase = (VOID *)OpenLibrary("graphics.library",LIBRARY_VERSION))) CloseAll(20); /* Fenster öffnen und richtig plazieren. */ if(!(Window = (struct Window *)OpenWindow(&NewWindow))) CloseAll(20); WindowToBack(Window); /* Kleine Information, falls das Fenster gerade aktiv ist. */ SetWindowTitles(Window,-1,NULL); /* ED-Symbol einzeichnen. */ DrawImage(Window -> RPort,&ClipImage,4,0); /* Sprites initialisieren. */ Position1 . height = 72; Position1 . x = 0; Position1 . y = 0; Position2 . height = 72; Position2 . x = 0; Position2 . y = 0; if(GetSprite(&Position1,2) < 0) CloseAll(20); if(GetSprite(&Position2,3) < 0) CloseAll(20); /* Mini-Zeichenbereich zum Vorbereiten der Sprites * initialisieren. */ InitBitMap(&PointerBMap,2,16,72); InitRastPort(&PointerRPort); PointerRPort . BitMap = &PointerBMap; for(i = 0 ; i < 2 ; i++) if(!(PointerBMap . Planes[i] = (PLANEPTR)AllocRaster(16,72))) CloseAll(20); /* Zeichensatz setzen und Zeichenfarbe einstellen. */ SetFont(&PointerRPort,OpenPixel6Font()); SetAPen(&PointerRPort,1); SetBPen(&PointerRPort,0); SetDrMd(&PointerRPort,JAM1); DoPosition = TRUE; /* Jetzt wird die Spritekontrolle aktiviert. */ AddVBlankServer(); } /* WhichDate() : * * Trägt das aktuelle Datum in eine Zeichenkette ein, * die später von uns genutzt werden wird. */ char * WhichDate() { static char Buff[10]; struct DateStamp Date; long n,Month,Day,Year; /* Tolle Technik nicht wahr? Stammt von ...äh, * Rob Peck... oder, hmm... Tom Rokicki? */ DateStamp(&Date); n = Date . ds_Days - 2251; Year = (4 * n + 3) / 1461; n -= 1461 * Year / 4; Year += 1984; Month = (5 * n + 2) / 153; Day = n - (153 * Month + 2) / 5 + 1; Month += 3; if(Month > 12) { Year++; Month -= 12; } Year -= 1900; /* Europäisches Format: Tag. Monat. Jahr */ sprintf(Buff,"%02d-%02d-%02d",Day,Month,Year); return(Buff); } /* WhichTime() : * * Trägt die aktuelle Zeit in eine Zeichenkette ein, die * wir später verwenden werden. */ char * WhichTime() { static char Buff[10]; struct DateStamp TimeStamp; long Hours,Minutes,Seconds; DateStamp(&TimeStamp); Hours = TimeStamp . ds_Minute / 60; Minutes = TimeStamp . ds_Minute % 60; Seconds = TimeStamp . ds_Tick / TICKS_PER_SECOND; /* 24 Stunden-Format. */ sprintf(Buff,"%2d:%02d:%02d",Hours,Minutes,Seconds); return(Buff); } /* WhichMem(Type) : * * Trägt den freien Speicher eines Typs in eine * Zeichenkette ein, die auch in die Sprites * einzeichnet werden wird. */ char * WhichMem(Type) long Type; { static char Buff[10]; long BlockSize; BlockSize = AvailMem(Type); sprintf(Buff,"%8d",BlockSize); return(Buff); } /* Diese beiden Zeilen schließen zwei Routinen aus, * die wir nicht benötigen; es spart zudem ein wenig * Speicher. */ void _cli_parse(){} void _wb_parse(){} /* MapToSprite(Sprite,BMap) : * * Wandelt den Inhalt einer Bitmap in ein Array * aus UWORDs um, das dem typischen Format eines * Hardwaresprites entspricht. */ void MapToSprite(Sprite,BMap) UWORD Sprite[]; struct BitMap *BMap; { register short i,j = 0; UWORD *Plane[2]; /* Ein Hardwaresprite hat ein recht "drolliges" * Format, das sich sonst in keiner anderen * Form auf dem Amiga findet: * * 2 UWORDs für Position und Kontrolldaten * n UWORDs für die eigentlich Spritedaten, * wobei sich die Daten für beide Planes * abwechseln. * 2 UWORDs für dubiose Zwecke. * * Die Daten für das Sprite folgen nicht wie auf * dem Amiga üblich blockweise, sondern Zeile * für Zeile gemischt. */ Plane[0] = (UWORD *)BMap -> Planes[0]; Plane[1] = (UWORD *)BMap -> Planes[1]; /* Spritedaten löschen. */ for(i = 0 ; i < 72 * 2 ; i++) Sprite[2 + i] = 0; /* Bitplanes in Sprite-Format wandeln. */ for(i = 0 ; i < 72 ; i++) for(j = 0 ; j < 2 ; j++) Sprite[2 + (2 * i) + j] = Plane[j][i]; } /* DoPtrTxt(Y,Txt) : * * Druckt einen Text in die Bitmap, die hinterher * in ein Sprite umgewandelt wird. Um den Kontrast * zu steigern, wird noch ein Schatten hinzugefügt. */ void DoPtrTxt(Y,Txt) LONG Y; char *Txt; { /* Schatten einzeichnen. */ Move(&PointerRPort,1,Y + 1); SetAPen(&PointerRPort,2); Text(&PointerRPort,Txt,4); /* Schrift einzeichnen. */ Move(&PointerRPort,0,Y); SetAPen(&PointerRPort,1); Text(&PointerRPort,Txt,4); } /* AdjustColours() : * * Die Farben der Anzeige von MouseClock sind von den * Farben des Mauszeigers abhängig. In dieser Funktion * werden sie aus den Preferences herauskopiert. */ void AdjustColours() { struct Preferences *Prefs; register short i; /* Puffer anlegen. */ if(Prefs = (struct Preferences *)AllocMem(sizeof(struct Preferences),MEMF_PUBLIC)) { /* Preferences kopieren. */ GetPrefs(Prefs,sizeof(struct Preferences)); /* Schattenfarbe in Komponenten aufsplitten. */ Shadow[0] = ((Prefs -> color18 >> 8) & 0xF); Shadow[1] = ((Prefs -> color18 >> 4) & 0xF); Shadow[2] = ((Prefs -> color18 ) & 0xF); /* Zeichenfarbe in Komponenten aufsplitten. */ Render[0] = ((Prefs -> color19 >> 8) & 0xF); Render[1] = ((Prefs -> color19 >> 4) & 0xF); Render[2] = ((Prefs -> color19 ) & 0xF); /* Puffer wieder freigeben. */ FreeMem(Prefs,sizeof(struct Preferences)); } } /* main() : * * Endlich! Nach soviel Vorbereitung nun schließlich * das Hauptprogramm. */ void main() { /* Fall MouseClock ein zweites Mal gestartet * wird, teilt es dem schon laufenden Task mit, daß * er sich entfernen soll. Diese Nachricht wird mit * den folgenden Strukturen verschickt. */ struct MsgPort *ReplyPort; struct Message WakeUp,*Terminate; struct DMSFragment *DMS = (struct DMSFragment *)FindPort("DMouse"); LONG MouseTimeout = 4; /* Zeichenpuffer, um die gewünschten Daten auf zwei * Sprites verteilen zu können. */ char DateBuff1[5],DateBuff2[5]; char TimeBuff1[5],TimeBuff2[5]; char FastBuff1[5],FastBuff2[5]; char ChipBuff1[5],ChipBuff2[5]; char *ptr; /* Letzte Position des Mauszeigers. */ LONG LastX = 0,LastY = 0; /* Wie oft lief die Prüfschleife schon durch, ohne * daß sich der Mauszeiger bewegte und wie * oft lief sie schon durch, ohne daß der Inhalt der * Sprites verändert werden mußte? */ LONG MoveCount = 0,i; /* Eingabeart, schon wieder so eine Erfindung von =RJ=, * was meint ihr, welchen Ärger ich mit ProSuite * hatte! Ich habe fast alles noch einmal schreiben * müssen, da die Hälfte der Includes zu nichts zu * gebrauchen war! */ ULONG Class; /* Falls schon eine MouseClock läuft, wird ihr * eine Nachricht zugesandt, die sie dazu veranlassen * soll, sich zu entfernen. */ if(MouseClockPort = (struct MsgPort *)FindPort("MouseClockPort",0)) { /* Die Rückantwort soll hier eingehen. */ if(!(ReplyPort = (struct MsgPort *)CreatePort(NULL,0))) exit(20); /* Nachricht initialisieren. */ WakeUp . mn_Node . ln_Type = NT_MESSAGE; WakeUp . mn_Length = sizeof(struct Message); WakeUp . mn_ReplyPort = ReplyPort; /* An den MessagePort schicken und * auf Bestätigung warten. */ PutMsg(MouseClockPort,&WakeUp); Wait(1 << ReplyPort -> mp_SigBit); /* Rückantwortsport löschen. */ DeletePort(ReplyPort); exit(0); } /* Alles öffnen und Farben der Sprites anpassen. */ OpenAll(); AdjustColours(); FOREVER { /* Sollen wir uns schon entfernen? */ if(Terminate = (struct Message *)GetMsg(MouseClockPort)) { ReplyMsg(Terminate); CloseAll(0); } if(DMS) if((MouseTimeout = DMS -> MTo - 1) < 0) MouseTimeout = 0; Class = NULL; /* Ist irgendetwas am Fenster passiert? */ if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort)) { Class = Massage -> Class; ReplyMsg(Massage); } /* Schließgadget gewählt? */ if(Class == CLOSEWINDOW) CloseAll(0); /* Die Farben des Mauszeigers könnten sich * geändert haben. */ if(Class == NEWPREFS) AdjustColours(); /* Das ED-Symbol muß nachgezeichnet werden. */ if(Class == REFRESHWINDOW) { BeginRefresh(Window); DrawImage(Window -> RPort,&ClipImage,4,0); EndRefresh(Window,TRUE); } /* Wir wurden aktiviert und melden uns * auch gleich. */ if(Class == ACTIVEWINDOW) { PrintIText(Window -> WScreen -> BarLayer -> rp,&AboutTxt[0],4,0); DrawImage(Window -> WScreen -> BarLayer -> rp,&ClipImage,210,0); } /* Wenn sich der Mauszeiger seit fünf * Sekunden nicht bewegt hat, wird die * Anzeige von MouseClock ausgeschaltet. * Bewegt sich der Mauszeiger anschließend * jedoch wieder, werden die Sprites * angeschaltet. */ if(CurX != LastX || CurY != LastY) { /* Sprites wieder anschalten. */ if(MoveCount > MouseTimeout) { GetSprite(&Position1,2); GetSprite(&Position2,3); DoPosition = TRUE; } MoveCount = 0; } else { if((++MoveCount) >= MouseTimeout) { /* Sprites ausschalten. */ if(MoveCount == MouseTimeout) { DoPosition = FALSE; WaitTOF(); WaitTOF(); FreeSprite(2); FreeSprite(3); } continue; } } /* Nur um sicherzugehen, daß wir es überhaupt * bemerken, wenn sich der Mauszeiger nicht * bewegt hat. */ LastX = CurX; LastY = CurY; /* Datum abfragen und aufspalten. */ ptr = WhichDate(); for(i = 0 ; i < 4 ; i++) { DateBuff1[i] = ptr[i]; DateBuff2[i] = ptr[i + 4]; } DateBuff1[4] = DateBuff2[4] = 0; /* Zeit abfragen und aufspalten. */ ptr = WhichTime(); for(i = 0 ; i < 4 ; i++) { TimeBuff1[i] = ptr[i]; TimeBuff2[i] = ptr[i + 4]; } TimeBuff1[4] = TimeBuff2[4] = 0; /* Chip-Ram abfragen und aufspalten. */ ptr = WhichMem(MEMF_CHIP); for(i = 0 ; i < 4 ; i++) { ChipBuff1[i] = ptr[i]; ChipBuff2[i] = ptr[i + 4]; } ChipBuff1[4] = ChipBuff2[4] = 0; /* Fast-Ram abfragen und aufspalten. */ ptr = WhichMem(MEMF_FAST); for(i = 0 ; i < 4 ; i++) { FastBuff1[i] = ptr[i]; FastBuff2[i] = ptr[i + 4]; } FastBuff1[4] = FastBuff2[4] = 0; /* Bitmap löschen und linkes * Sprite erzeugen. */ SetRast(&PointerRPort,0); DoPtrTxt(10,TimeBuff2); DoPtrTxt(22,DateBuff2); DoPtrTxt(34,ChipBuff2); DoPtrTxt(46,FastBuff2); MapToSprite(Pointer2Data,&PointerBMap); /* Bitmap löschen und rechtes * Sprite erzeugen. */ SetRast(&PointerRPort,0); DoPtrTxt(4,"TIME"); DoPtrTxt(10,TimeBuff1); DoPtrTxt(16,"DATE"); DoPtrTxt(22,DateBuff1); DoPtrTxt(28,"CHIP"); DoPtrTxt(34,ChipBuff1); DoPtrTxt(40,"FAST"); DoPtrTxt(46,FastBuff1); MapToSprite(Pointer1Data,&PointerBMap); /* Neue Sprites anzeigen. */ ChangeSprite(NULL,&Position1,Pointer1Data); ChangeSprite(NULL,&Position2,Pointer2Data); /* Eine Zeitperiode warten. */ WaitTime(1,0); } }