home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff279.lzh / MouseClock / MouseClock.c < prev    next >
C/C++ Source or Header  |  1989-11-20  |  27KB  |  1,182 lines

  1. /* MouseClock.c *************************************************************
  2. *
  3. *    MouseClock ----    Ein Uhren-Utility, das ausnahmsweise nicht
  4. *            irgendwo auf einem obskuren Bildschirm
  5. *            (meinetwegen auch Workbench-Bildschirm)
  6. *            existiert, sondern sich in der Nähe des
  7. *            Mauszeigers aufhält. Die Position und
  8. *            der Bildschirm, auf dem sich die Anzeige
  9. *            von MouseClock aufhält, ist unabhängig vom
  10. *            Workbench-Bildschirm. Ähnlich wie beim
  11. *            Mauszeiger liegen die Sprites, die Mouseclock
  12. *            zur Anzeige verwendet, immer auf dem vordersten
  13. *            Bildschirm.
  14. *
  15. *            Besonders stolz (soviel Eitelkeit darf ich
  16. *            mir hoffentlich gönnen) bin ich auf den Interrupt-
  17. *            code, der die Anzeige bewegt. Es hat auf
  18. *            Anhieb geklappt und ist noch nicht ein einziges
  19. *            mal abgeschmiert.
  20. *
  21. *    Autor ---------    Olaf Barthel, ED Electronic Design Hannover
  22. *            Brabeckstraße 35
  23. *            D-3000 Hannover 71
  24. *
  25. *            Bundesrepublik Deutschland
  26. *
  27. *            (C) Copyright 1989 by Olaf Barthel &
  28. *                ED Electronic Design Hannover
  29. *
  30. ****************************************************************************/
  31.  
  32. #include <intuition/intuitionbase.h>
  33. #include <libraries/dosextens.h>
  34. #include <graphics/gfxbase.h>
  35. #include <exec/interrupts.h>
  36. #include <graphics/sprite.h>
  37. #include <devices/timer.h>
  38. #include <exec/memory.h>
  39.  
  40.     /* Vorwärtsdeklarationen, um Compiler-Warnungen zu
  41.      * zu vermeiden.
  42.      */
  43.  
  44. extern struct Library    *OpenLibrary();
  45. extern struct Window    *OpenWindow();
  46. extern struct ViewPort    *ViewPortAddress();
  47. extern struct Message    *GetMsg();
  48. extern struct MsgPort    *CreatePort();
  49. extern struct MsgPort    *FindPort();
  50. extern void        *AllocMem();
  51. extern PLANEPTR        AllocRaster();
  52. extern long        AvailMem();
  53.  
  54.     /* Globale Variablen, die zur Handhabung des Displays
  55.      * und des Fensters dienen.
  56.      */
  57.  
  58. struct IntuitionBase    *IntuitionBase;
  59. struct GfxBase        *GfxBase;
  60. struct Window        *Window;
  61. struct IntuiMessage    *Massage;
  62. struct MsgPort        *MouseClockPort;
  63.  
  64.     /* Wir orientieren uns zwar nicht am vordersten ViewPort,
  65.      * wenn wir die Sprites setzen, passen aber die Farben
  66.      * der Sprites an, wenn ein Bildschirm weniger als 32
  67.      * Farben hat.
  68.      */
  69.  
  70. struct ViewPort *VPort;
  71.  
  72.     /* Die beiden Sprites der Anzeige. */
  73.  
  74. struct SimpleSprite Position1,Position2;
  75.  
  76.     /* Mit diesen Variablen wird später Schrift in die Sprites
  77.      * gedruckt.
  78.      */
  79.  
  80. struct BitMap    PointerBMap;
  81. struct RastPort    PointerRPort;
  82.  
  83.     /* Aktuelle Position des Mauszeigers, soll die Interruptroutine
  84.      * den Mauszeiger bearbeiten?
  85.      */
  86.  
  87. WORD CurX,CurY,DoPosition = FALSE;
  88.  
  89.     /* Datenspeicher für die Spritedaten. */
  90.  
  91. UWORD Pointer1Data[(2 + 72) * 2],Pointer2Data[(2 + 72) * 2];
  92.  
  93.     /* Zeichenfarben für Schrift und Hintergrund. */
  94.  
  95. UBYTE Render[3],Shadow[3];
  96.  
  97.     /* Mit den folgenden Daten werden Fonts zum Zeichnen der
  98.      * Kurzinfo definiert.
  99.      */
  100.  
  101. struct TextAttr AboutFont[3] =
  102. {
  103.     {(UBYTE *)"topaz.font",8,FS_NORMAL ,FPF_ROMFONT},
  104.     {(UBYTE *)"topaz.font",8,FSF_BOLD  ,FPF_ROMFONT},
  105.     {(UBYTE *)"topaz.font",8,FSF_ITALIC,FPF_ROMFONT}
  106. };
  107.  
  108.     /* Dies ist die "Kurzinfo", die gezeigt wird, wenn unser
  109.      * Fenster aktiviert worden ist. Der Titlebar des
  110.      * Workbench-Bildschirms wird ein wenig verschönert.
  111.      */
  112.  
  113. struct IntuiText AboutTxt[4] =
  114. {
  115.     {3,1,JAM1,  0,1,(struct TextAttr *)&AboutFont[1],(UBYTE *)"MouseClock",            (struct IntuiText *)&AboutTxt[ 1]},
  116.     {2,1,JAM1, 88,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"v1.2",            (struct IntuiText *)&AboutTxt[ 2]},
  117.     {2,1,JAM1,128,1,(struct TextAttr *)&AboutFont[0],(UBYTE *)"© 1989 by",            (struct IntuiText *)&AboutTxt[ 3]},
  118.     {0,1,JAM1,232,1,(struct TextAttr *)&AboutFont[2],(UBYTE *)"Electronic Design Hannover",    (struct IntuiText *)NULL}
  119. };
  120.  
  121.     /* Bitmapdaten um das ED-Symbol über dem Schließgadget
  122.      * zeichnen zu können.
  123.      */
  124.  
  125. USHORT ClipMap[40] =
  126. {
  127.     0xFFFF,0xF000,0xFFFF,0xF000,0xF001,0xF000,0xF7FF,0xF000,
  128.     0xFFFF,0xD000,0xF03F,0xD000,0xF7FF,0x9000,0xFFFF,0x3000,
  129.     0xF000,0x7000,0xFFFF,0xF000,
  130.  
  131.     0x0000,0x0000,0x1FFF,0x0000,0x3FFF,0x8000,0x3800,0xC000,
  132.     0x1F80,0xE000,0x3FC0,0xE000,0x3801,0xE000,0x1FFF,0xC000,
  133.     0x0FFF,0x8000,0x0000,0x0000
  134. };
  135.  
  136.     /* Zum Einzeichnen des ED-Symbols notwendige Definition. */
  137.  
  138. struct Image ClipImage =
  139. {
  140.     0,0,
  141.     20,10,2,
  142.     (USHORT *)ClipMap,
  143.     0x03,0x00,
  144.     (struct Image *)NULL
  145. };
  146.  
  147.     /* Dieses Fenster wird geöffnet, um u.A. festellen zu
  148.      * können, ob der Anwender das Programm beenden möchte,
  149.      * oder sich die Farbe des Mauszeigers geändert hat.
  150.      */
  151.  
  152. struct NewWindow NewWindow =
  153. {
  154.     561,0,
  155.     26,10,
  156.     1,1,
  157.     CLOSEWINDOW | NEWPREFS | REFRESHWINDOW | ACTIVEWINDOW,
  158.     RMBTRAP | WINDOWCLOSE | SIMPLE_REFRESH,
  159.     (struct Gadget *)NULL,
  160.     (struct Image *)NULL,
  161.     (STRPTR)NULL,
  162.     (struct Screen *)NULL,
  163.     (struct BitMap *)NULL,
  164.     0,0,
  165.     0,0,
  166.     WBENCHSCREEN
  167. };
  168.  
  169.     /* Falls sich DMouse irgendwo im Speicher versteckt, borgen
  170.      * wir den DMouse Mousetimeout, um die Sprites rechtzeitig
  171.      * verschwinden zu lassen.
  172.      */
  173.  
  174. struct DMSFragment
  175. {
  176.     struct MsgPort    Port;    /* Globaler Messageport. */
  177.     short        Version;/* Aktuelle Version. */
  178.     short        Acc;    /* Beschleunigung. */
  179.     short        AThresh;/* Beschleunigungsschwelle. */
  180.     long        STo;    /* Screentimeout. */
  181.     long        MTo;    /* Mousetimeout. */
  182. };
  183.  
  184.     /* Diese Variablen sind notwendig, wenn man sich vom
  185.      * CLI abkoppeln möchte, von dem man gestartet wird.
  186.      */
  187.  
  188. long  _stack        = 4000;
  189. long  _priority        = 1;
  190. long  _BackGroundIO    = NULL;
  191. char *_procname        = "MouseClock v1.2";
  192.  
  193.     /* Hilfsstrukturen zur Kontrolle des timer.device. */
  194.  
  195. struct timerequest    *tr_TimerRequest= NULL;
  196. struct MsgPort        *tr_TimerPort    = NULL;
  197.  
  198.     /* Mit dieser Struktur wird die Routine zum Positionieren
  199.      * der Anzeige in den Vertical Blanking Interrupt gehängt.
  200.      */
  201.  
  202. struct Interrupt VBlankServer;
  203.  
  204.     /* Da wir diese Symbole noch brauchen, um in einigen
  205.      * Assemblerroutinen herumzukleistern, aber die Assembler-
  206.      * routinen, die gleich folgen werden, diese Symbole für
  207.      * den Compiler nicht sichtbar erzeugen, schustern wir
  208.      * ein wenig herum.
  209.      */
  210.  
  211. extern void NuCloseScreen();
  212. extern void HandleVBlank();
  213.  
  214.     /* Hier wird später einmal ein Zeiger auf eine System-
  215.      * routine erscheinen, OpenScreen() um genau zu sein.
  216.      * Dieser Wert wird von SetFunction() zurückgeliefert,
  217.      * wenn wir in den Libraries herumstochern.
  218.      */
  219.  
  220. long OldCloseScreen;
  221.  
  222. #asm
  223. _HandleVBlank:    MOVEM.L    A2-A6/D2-D7,-(A7)    ; Ein paar Register retten
  224.  
  225.         JSR    _geta4#            ; Adressregister geraderücken
  226.         JSR    _MyHandleVBlank        ; C-Routine anspringen
  227.  
  228.         CLR.L    D0            ; Da wir im Interrupt sind,
  229.                         ; muß D0 gelöscht werden.
  230.  
  231.         MOVEM.L    (A7)+,A2-A6/D2-D7    ; Die Register restaurieren
  232.  
  233.         RTS                ; ...und weiter.
  234.  
  235. _NuCloseScreen:    MOVEM.L    D2/D3/A4/A6,-(SP)    ; Ein paar Register retten
  236.  
  237.         MOVE.L    A0,-(SP)        ; Screen-Zeiger als Argument
  238.                         ; übernehmen
  239.  
  240.         JSR    _geta4#            ; Adressregister geraderücken
  241.         JSR    _ModifiedCloseScreen    ; C-Routine anspringen
  242.  
  243.         ADDQ.L    #4,SP            ; Stack korrigieren
  244.         MOVE.L  D0,A0            ; Screen weiterleiten
  245.  
  246.         MOVE.L  _OldCloseScreen,A1    ; Alte Routine merken
  247.  
  248.         MOVEM.L    (SP)+,D2/D3/A4/A6    ; Register restaurieren
  249.  
  250.         JMP    (A1)            ; Alte Routine anspringen
  251. #endasm
  252.  
  253.     /* ModifiedCloseScreen(Screen) :
  254.      *
  255.      *    Ein Patch für die CloseScreen() Routine, damit
  256.      *    sich die Interrupt-Routine nicht an Bildschirme
  257.      *    heranmacht, die gerade geschlossen werden.
  258.      */
  259.  
  260. struct Screen *
  261. ModifiedCloseScreen(Screen)
  262. struct Screen *Screen;
  263. {
  264.         /* Bildschirm nach hinten legen. */
  265.  
  266.     ScreenToBack(Screen);
  267.  
  268.         /* Zweimal auf den Durchlauf des Vertical Blanking
  269.          * warten, damit der Handler auch wirklich mitkriegt,
  270.          * daß er einen Bildschirm nicht manipulieren kann,
  271.          * den es in Zehntelsekunden nicht mehr geben wird.
  272.          * Gut, das ist die kompliziertere Methode, aber
  273.          * wenigstens geht sie nicht immer in die Hose,
  274.          * was ohne diesen Patch sehr häufig passiert.
  275.          */
  276.  
  277.     WaitTOF();
  278.     WaitTOF();
  279.  
  280.         /* Man kann ja nicht immer alles auf dem Stack
  281.          * herumliegen lassen, also liefern wir den Zeiger
  282.          * zurück, damit die alte CloseScreen() Routine
  283.          * nicht im Regen steht.
  284.          */
  285.  
  286.     return(Screen);
  287. }
  288.  
  289.     /* MyHandleVBlank() :
  290.      *
  291.      *    Dies ist eine echte Interrupt-Routine in C,
  292.      *    ja das gibt es wirklich und es funktioniert
  293.      *    sogar. In dieser Routine werden die Sprites
  294.      *    bewegt und die Farben gesetzt. Auf diese
  295.      *    Weise ist es wesentlich schneller als eine
  296.      *    multitaskingfähige Unterroutine, die z.B.
  297.      *    auf das timer.device wartet.
  298.      */
  299.  
  300. void
  301. MyHandleVBlank()
  302. {
  303.         /* WER konnte es ahnen, daß Intuition diese
  304.          * Daten auf einen Bildschirm bezieht, der
  305.          * 640 Pixel in X-Richtung und 512 in Y-Richtung
  306.          * besitzt? Es hat mich eine Menge Zeit gekostet,
  307.          * herauszufinden, weshalb sich die Anzeige
  308.          * schneller bewegte als der Mauszeiger selbst,
  309.          * bis ich herausbekam, daß diese Daten
  310.          * nicht für Sprites gedacht sind, die sich nur
  311.          * in Lo-res Schritten bewegen können.
  312.          */
  313.  
  314.     CurX = IntuitionBase -> MouseX >> 1;
  315.     CurY = IntuitionBase -> MouseY >> 1;
  316.  
  317.         /* Falls nötig, werden die Farben der Sprites
  318.          * an den aktuellen Bildschirm angepaßt.
  319.          */
  320.  
  321.     VPort = &IntuitionBase -> FirstScreen -> ViewPort;
  322.  
  323.         /* Na woher wissen wir denn, wie tief der Bildschirm
  324.          * ist? Na, wozu hängt eine RasInfo am ViewPort?
  325.          */
  326.  
  327.     if(VPort -> RasInfo -> BitMap -> Depth < 5)
  328.     {
  329.         SetRGB4(VPort,22,Shadow[0],Shadow[1],Shadow[2]);
  330.         SetRGB4(VPort,21,Render[0],Render[1],Render[2]);
  331.     }
  332.  
  333.     if(DoPosition)
  334.     {
  335.         /* Sprites an die Position rechts neben dem
  336.          * Mauszeiger rücken.
  337.          */
  338.  
  339.         MoveSprite(NULL,&Position1,CurX + 8,CurY);
  340.         MoveSprite(NULL,&Position2,CurX + 24,CurY);
  341.     }
  342. }
  343.  
  344.     /* AddVBlankServer() :
  345.      *
  346.      *    Dies initialisiert eine Struktur, mit deren Hilfe
  347.      *    ein Interruptserver in den Vertical Blanking
  348.      *    Interrupt eingeklinkt wird.
  349.      */
  350.  
  351. void
  352. AddVBlankServer()
  353. {
  354.     VBlankServer . is_Data        = (APTR)NULL;
  355.     VBlankServer . is_Code        = HandleVBlank;
  356.     VBlankServer . is_Node . ln_Succ= NULL;
  357.     VBlankServer . is_Node . ln_Pred= NULL;
  358.     VBlankServer . is_Node . ln_Type= NT_INTERRUPT;
  359.     VBlankServer . is_Node . ln_Pri    = 0;
  360.     VBlankServer . is_Node . ln_Name= "MouseClock";
  361.  
  362.         /* Herzlichen Dank an Dan Silva, er benutzt eine
  363.          * ähnliche Methode, um DPaint Colourcycling
  364.          * beizubringen. Ich hab's einfach einmal
  365.          * ausprobiert und es lief sofort!
  366.          */
  367.  
  368.     AddIntServer(5,&VBlankServer);
  369. }
  370.  
  371.     /* RemVBlankServer() :
  372.      *
  373.      *    Wirft den Interruptserver wieder aus der Liste
  374.      *    der Interrupts.
  375.      */
  376.  
  377. void
  378. RemVBlankServer()
  379. {
  380.         /* Hoffentlich baut Exec keinen Mist und
  381.          * schickt den Server wirklich in die Wüste.
  382.          */
  383.  
  384.     RemIntServer(5,&VBlankServer);
  385. }
  386.  
  387.     /* OpenTimerDevice() :
  388.      *
  389.      *    Öffnet das timer.device für unsere Zwecke.
  390.      */
  391.  
  392. BOOL
  393. OpenTimerDevice()
  394. {
  395.     if(!(tr_TimerPort = (struct MsgPort *)CreatePort(NULL,0)))
  396.         return(FALSE);
  397.  
  398.     if(!(tr_TimerRequest = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC | MEMF_CLEAR)))
  399.     {
  400.         DeletePort(tr_TimerPort);
  401.  
  402.         return(FALSE);
  403.     }
  404.  
  405.         /* Präzisionszeitgeber aktivieren. */
  406.  
  407.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,tr_TimerRequest,0))
  408.     {
  409.         FreeMem(tr_TimerRequest,(long)sizeof(struct timerequest));
  410.         DeletePort(tr_TimerPort);
  411.  
  412.         return(FALSE);
  413.     }
  414.  
  415.     tr_TimerRequest -> tr_node . io_Message . mn_ReplyPort    = tr_TimerPort;
  416.     tr_TimerRequest -> tr_node . io_Command            = TR_ADDREQUEST;
  417.     tr_TimerRequest -> tr_node . io_Flags            = 0;
  418.     tr_TimerRequest -> tr_node . io_Error            = 0;
  419.  
  420.     return(TRUE);
  421. }
  422.  
  423.     /* CloseTimerDevice() :
  424.      *
  425.      *    Gibt den angeforderten Speicher frei und schließt das
  426.      *    timer.device.
  427.      */
  428.  
  429. void
  430. CloseTimerDevice()
  431. {
  432.     if(tr_TimerRequest)
  433.     {
  434.         CloseDevice(tr_TimerRequest);
  435.         FreeMem(tr_TimerRequest,sizeof(struct timerequest));
  436.     }
  437.  
  438.     if(tr_TimerPort)
  439.         DeletePort(tr_TimerPort);
  440. }
  441.  
  442.     /* WaitTime(Seconds,Micros) :
  443.      *
  444.      *    Wartet eine Zeitperiode.
  445.      */
  446.  
  447. void
  448. WaitTime(Seconds,Micros)
  449. register ULONG Seconds,Micros;
  450. {
  451.     tr_TimerRequest -> tr_time . tv_secs    = Seconds;
  452.     tr_TimerRequest -> tr_time . tv_micro    = Micros;
  453.  
  454.     DoIO(tr_TimerRequest);
  455. }
  456.  
  457.     /* OpenPixel6Font() :
  458.      *
  459.      *    Aktiviert einen speziellen, 4 Pixel breiten und
  460.      *    6 Zeilen hohen Zeichensatz, mit dem später in die
  461.      *    Sprites gezeichnet wird.
  462.      */
  463.  
  464. struct TextFont *
  465. OpenPixel6Font()
  466. {
  467.     static struct TextFont Pixel6Font;
  468.  
  469.     static long Pixel6Dump[138] =
  470.     {
  471.         0x04AA2240,0x00002E2E,0xEAEEEEE0,0x0204E4C4,
  472.         0xCEE6AE2A,0x8AA4C4C6,0xEAAAAAE6,0x864004A2,
  473.         0x242A4000,0x2A222A88,0x2AA444E2,0x2AAAA888,
  474.         0xA42A8ECA,0xAAA84AAA,0xAA2482A0,0x04044424,
  475.         0xE0E04A2E,0xEEEE2EE0,0x08016EC8,0xAEEAE42C,
  476.         0x8EEACAC4,0x4AAE4444,0x42000008,0x042A4400,
  477.         0x8A28222A,0x2A2444E2,0x0AAAA88A,0xA4AA8A6A,
  478.         0x8AA24AAE,0xA4842200,0x040A0240,0x04048E2E,
  479.         0xE2EE2EE0,0x42044AC4,0xCE86AE4A,0xEAA487AC,
  480.         0x464AA4E6,0x26000000,0x00000800,0x00000000,
  481.         0x00008000,0x00000000,0x00000000,0x00000000,
  482.         0x0000000F,0x00000004,0x00040004,0x00080004,
  483.         0x00000004,0x00000004,0x000C0004,0x00000004,
  484.         0x00100004,0x00140004,0x00180004,0x001C0004,
  485.         0x00200004,0x00240004,0x00280004,0x002C0004,
  486.         0x00300004,0x00340004,0x00380004,0x003C0004,
  487.         0x00400004,0x00440004,0x00480004,0x004C0004,
  488.         0x00500004,0x00540004,0x00580004,0x005C0004,
  489.         0x00600004,0x00640004,0x00680004,0x006C0004,
  490.         0x00700004,0x00000004,0x00740004,0x00780004,
  491.         0x007C0004,0x00800004,0x00840004,0x00880004,
  492.         0x008C0004,0x00900004,0x00940004,0x00980004,
  493.         0x009C0004,0x00A00004,0x00A40004,0x00A80004,
  494.         0x00AC0004,0x00B00004,0x00B40004,0x00B80004,
  495.         0x00BC0004,0x00C00004,0x00C40004,0x00C80004,
  496.         0x00CC0004,0x00D00004,0x00D40004,0x00D80004,
  497.         0x00DC0004,0x00E00004,0x00E40004,0x00E80004,
  498.         0x00EC0004,0x00540004,0x005400C3,0x66E00000,
  499.         0x04002C30,0x78303035,0x43303030,0x342C0A09,
  500.         0x09307830,0x30363030,0x3030342C,0x30783030,
  501.         0x36343030,0x30342C30,0x78303036,0x38303030,
  502.         0x342C3078,0x30303643,0x30303034,0x2C0A0909,
  503.         0x30783030,0x37303030,0x30342C30,0x78303030,
  504.         0x30303030,0x342C3078,0x30303734,0x30303034,
  505.         0x2C307830,0x30373830
  506.     };
  507.  
  508.     Pixel6Font . tf_Message . mn_Node . ln_Name = "Pixel.font";
  509.     Pixel6Font . tf_Message . mn_Node . ln_Type = NT_FONT;
  510.     Pixel6Font . tf_Message . mn_Node . ln_Pri  = 0;
  511.  
  512.     Pixel6Font . tf_YSize     = 6;
  513.     Pixel6Font . tf_Style     = 0;
  514.     Pixel6Font . tf_Flags     = 66;
  515.     Pixel6Font . tf_XSize     = 4;
  516.     Pixel6Font . tf_Baseline  = 4;
  517.     Pixel6Font . tf_BoldSmear = 1;
  518.     Pixel6Font . tf_Accessors = 0;
  519.     Pixel6Font . tf_LoChar    = 32;
  520.     Pixel6Font . tf_HiChar    = 95;
  521.     Pixel6Font . tf_CharData  = (APTR)&Pixel6Dump[0];
  522.     Pixel6Font . tf_Modulo    = 30;
  523.     Pixel6Font . tf_CharLoc   = (APTR)((char *)&Pixel6Dump[0] + (0xC4EE3A - 0xC4ED86));
  524.     Pixel6Font . tf_CharSpace = 0;
  525.     Pixel6Font . tf_CharKern  = 0;
  526.  
  527.     return(&Pixel6Font);
  528. }
  529.  
  530.     /* CloseAll(ReturnCode) :
  531.      *
  532.      *    Gibt allen angeforderten Speicher frei, schließt
  533.      *    Libraries, Devices, Fenster, etc. und verläßt das
  534.      *    Programm.
  535.      */
  536.  
  537. void
  538. CloseAll(ReturnCode)
  539. long ReturnCode;
  540. {
  541.     register short i;
  542.  
  543.     DoPosition = FALSE;
  544.  
  545.         /* Die beiden Sprites brauchen wir nicht mehr. Deshalb
  546.          * ab in die Wüste damit.
  547.          */
  548.  
  549.     FreeSprite(2);
  550.     FreeSprite(3);
  551.  
  552.     if(Window)
  553.     {
  554.         while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  555.             ReplyMsg(Massage);
  556.  
  557.         CloseWindow(Window);
  558.     }
  559.  
  560.         /* Bitmapdaten freigeben. */
  561.  
  562.     for(i = 0 ; i < 2 ; i++)
  563.         if(PointerBMap . Planes[i])
  564.             FreeRaster(PointerBMap . Planes[i],16,72);
  565.  
  566.     if(IntuitionBase)
  567.     {
  568.             /* Intuition wieder Kontrolle über die
  569.              * eigenen Routinen geben.
  570.              */
  571.  
  572.         Forbid();
  573.         SetFunction(IntuitionBase,-0x42,OldCloseScreen);
  574.         Permit();
  575.  
  576.         CloseLibrary(IntuitionBase);
  577.     }
  578.  
  579.     if(GfxBase)
  580.         CloseLibrary(GfxBase);
  581.  
  582.     CloseTimerDevice();
  583.  
  584.         /* Den MessagePort, mit dem wir erreichbar waren,
  585.          * schließen.
  586.          */
  587.  
  588.     if(MouseClockPort)
  589.         DeletePort(MouseClockPort);
  590.  
  591.     RemVBlankServer();
  592.  
  593.     exit(ReturnCode);
  594. }
  595.  
  596.     /* OpenAll() :
  597.      *
  598.      *    Öffnet alles, was geöffnet werden muß und
  599.      *    bereitet Speicher vor, den wir später brauchen
  600.      *    werden.
  601.      */
  602.  
  603. void
  604. OpenAll()
  605. {
  606.     register short i;
  607.  
  608.     if(!(MouseClockPort = (struct MsgPort *)CreatePort("MouseClockPort",0)))
  609.         CloseAll(20);
  610.  
  611.     if(!OpenTimerDevice())
  612.         CloseAll(20);
  613.  
  614.     if(!(IntuitionBase = (VOID *)OpenLibrary("intuition.library",LIBRARY_VERSION)))
  615.         CloseAll(20);
  616.  
  617.         /* Jetzt hängen wir unsere eigene CloseScreen()
  618.          * Routine ins System.
  619.          */
  620.  
  621.     Forbid();
  622.     OldCloseScreen = SetFunction(IntuitionBase,-0x42,NuCloseScreen);
  623.     Permit();
  624.  
  625.     if(!(GfxBase = (VOID *)OpenLibrary("graphics.library",LIBRARY_VERSION)))
  626.         CloseAll(20);
  627.  
  628.         /* Fenster öffnen und richtig plazieren. */
  629.  
  630.     if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
  631.         CloseAll(20);
  632.  
  633.     WindowToBack(Window);
  634.  
  635.         /* Kleine Information, falls das Fenster gerade aktiv ist. */
  636.  
  637.     SetWindowTitles(Window,-1,NULL);
  638.  
  639.         /* ED-Symbol einzeichnen. */
  640.  
  641.     DrawImage(Window -> RPort,&ClipImage,4,0);
  642.  
  643.         /* Sprites initialisieren. */
  644.  
  645.     Position1 . height    = 72;
  646.     Position1 . x        = 0;
  647.     Position1 . y        = 0;
  648.  
  649.     Position2 . height    = 72;
  650.     Position2 . x        = 0;
  651.     Position2 . y        = 0;
  652.  
  653.     if(GetSprite(&Position1,2) < 0)
  654.         CloseAll(20);
  655.  
  656.     if(GetSprite(&Position2,3) < 0)
  657.         CloseAll(20);
  658.  
  659.         /* Mini-Zeichenbereich zum Vorbereiten der Sprites
  660.          * initialisieren.
  661.          */
  662.  
  663.     InitBitMap(&PointerBMap,2,16,72);
  664.     InitRastPort(&PointerRPort);
  665.  
  666.     PointerRPort . BitMap = &PointerBMap;
  667.  
  668.     for(i = 0 ; i < 2 ; i++)
  669.         if(!(PointerBMap . Planes[i] = (PLANEPTR)AllocRaster(16,72)))
  670.             CloseAll(20);
  671.  
  672.         /* Zeichensatz setzen und Zeichenfarbe einstellen. */
  673.  
  674.     SetFont(&PointerRPort,OpenPixel6Font());
  675.  
  676.     SetAPen(&PointerRPort,1);
  677.     SetBPen(&PointerRPort,0);
  678.     SetDrMd(&PointerRPort,JAM1);
  679.  
  680.     DoPosition = TRUE;
  681.  
  682.         /* Jetzt wird die Spritekontrolle aktiviert. */
  683.  
  684.     AddVBlankServer();
  685. }
  686.  
  687.     /* WhichDate() :
  688.      *
  689.      *    Trägt das aktuelle Datum in eine Zeichenkette ein,
  690.      *    die später von uns genutzt werden wird.
  691.      */
  692.  
  693. char *
  694. WhichDate()
  695. {
  696.     static char Buff[10];
  697.     struct DateStamp Date;
  698.     long n,Month,Day,Year;
  699.  
  700.         /* Tolle Technik nicht wahr? Stammt von ...äh,
  701.          * Rob Peck... oder, hmm... Tom Rokicki?
  702.          */
  703.  
  704.     DateStamp(&Date);
  705.  
  706.     n = Date . ds_Days - 2251;
  707.     Year = (4 * n + 3) / 1461;
  708.     n -= 1461 * Year / 4;
  709.     Year += 1984;
  710.     Month = (5 * n + 2) / 153;
  711.     Day = n - (153 * Month + 2) / 5 + 1;
  712.     Month += 3;
  713.  
  714.     if(Month > 12)
  715.     {
  716.         Year++;
  717.         Month -= 12;
  718.     }
  719.  
  720.     Year -= 1900;
  721.  
  722.         /* Europäisches Format: Tag. Monat. Jahr */
  723.  
  724.     sprintf(Buff,"%02d-%02d-%02d",Day,Month,Year);
  725.  
  726.     return(Buff);
  727. }
  728.  
  729.     /* WhichTime() :
  730.      *
  731.      *    Trägt die aktuelle Zeit in eine Zeichenkette ein, die
  732.      *    wir später verwenden werden.
  733.      */
  734.  
  735. char *
  736. WhichTime()
  737. {
  738.     static char Buff[10];
  739.  
  740.     struct DateStamp TimeStamp;
  741.     long Hours,Minutes,Seconds;
  742.  
  743.     DateStamp(&TimeStamp);
  744.  
  745.     Hours    = TimeStamp . ds_Minute / 60;
  746.     Minutes    = TimeStamp . ds_Minute % 60;
  747.     Seconds    = TimeStamp . ds_Tick / TICKS_PER_SECOND;
  748.  
  749.         /* 24 Stunden-Format. */
  750.  
  751.     sprintf(Buff,"%2d:%02d:%02d",Hours,Minutes,Seconds);
  752.  
  753.     return(Buff);
  754. }
  755.  
  756.     /* WhichMem(Type) :
  757.      *
  758.      *    Trägt den freien Speicher eines Typs in eine
  759.      *    Zeichenkette ein, die auch in die Sprites
  760.      *    einzeichnet werden wird.
  761.      */
  762.  
  763. char *
  764. WhichMem(Type)
  765. long Type;
  766. {
  767.     static char Buff[10];
  768.  
  769.     long BlockSize;
  770.  
  771.     BlockSize = AvailMem(Type);
  772.  
  773.     sprintf(Buff,"%8d",BlockSize);
  774.  
  775.     return(Buff);
  776. }    
  777.  
  778.     /* Diese beiden Zeilen schließen zwei Routinen aus,
  779.      * die wir nicht benötigen; es spart zudem ein wenig
  780.      * Speicher.
  781.      */
  782.  
  783. void _cli_parse(){}
  784. void _wb_parse(){}
  785.  
  786.     /* MapToSprite(Sprite,BMap) :
  787.      *
  788.      *    Wandelt den Inhalt einer Bitmap in ein Array
  789.      *    aus UWORDs um, das dem typischen Format eines
  790.      *    Hardwaresprites entspricht.
  791.      */
  792.  
  793. void
  794. MapToSprite(Sprite,BMap)
  795. UWORD Sprite[];
  796. struct BitMap *BMap;
  797. {
  798.     register short i,j = 0;
  799.     UWORD *Plane[2];
  800.  
  801.         /* Ein Hardwaresprite hat ein recht "drolliges"
  802.          * Format, das sich sonst in keiner anderen
  803.          * Form auf dem Amiga findet:
  804.          *
  805.          *    2 UWORDs für Position und Kontrolldaten
  806.          *    n UWORDs für die eigentlich Spritedaten,
  807.          *      wobei sich die Daten für beide Planes
  808.          *      abwechseln.
  809.          *    2 UWORDs für dubiose Zwecke.
  810.          *
  811.          * Die Daten für das Sprite folgen nicht wie auf
  812.          * dem Amiga üblich blockweise, sondern Zeile
  813.          * für Zeile gemischt.
  814.          */
  815.  
  816.     Plane[0] = (UWORD *)BMap -> Planes[0];
  817.     Plane[1] = (UWORD *)BMap -> Planes[1];
  818.  
  819.         /* Spritedaten löschen. */
  820.  
  821.     for(i = 0 ; i < 72 * 2 ; i++)
  822.         Sprite[2 + i] = 0;
  823.  
  824.         /* Bitplanes in Sprite-Format wandeln. */
  825.  
  826.     for(i = 0 ; i < 72 ; i++)
  827.         for(j = 0 ; j < 2 ; j++)
  828.             Sprite[2 + (2 * i) + j] = Plane[j][i];
  829. }
  830.  
  831.     /* DoPtrTxt(Y,Txt) :
  832.      *
  833.      *    Druckt einen Text in die Bitmap, die hinterher
  834.      *    in ein Sprite umgewandelt wird. Um den Kontrast
  835.      *    zu steigern, wird noch ein Schatten hinzugefügt.
  836.      */
  837.  
  838. void
  839. DoPtrTxt(Y,Txt)
  840. LONG Y;
  841. char *Txt;
  842. {
  843.         /* Schatten einzeichnen. */
  844.  
  845.     Move(&PointerRPort,1,Y + 1);
  846.     SetAPen(&PointerRPort,2);
  847.     Text(&PointerRPort,Txt,4);
  848.  
  849.         /* Schrift einzeichnen. */
  850.  
  851.     Move(&PointerRPort,0,Y);
  852.     SetAPen(&PointerRPort,1);
  853.     Text(&PointerRPort,Txt,4);
  854. }
  855.  
  856.     /* AdjustColours() :
  857.      *
  858.      *    Die Farben der Anzeige von MouseClock sind von den
  859.      *    Farben des Mauszeigers abhängig. In dieser Funktion
  860.      *    werden sie aus den Preferences herauskopiert.
  861.      */
  862.  
  863. void
  864. AdjustColours()
  865. {
  866.     struct Preferences *Prefs;
  867.     register short i;
  868.  
  869.         /* Puffer anlegen. */
  870.  
  871.     if(Prefs = (struct Preferences *)AllocMem(sizeof(struct Preferences),MEMF_PUBLIC))
  872.     {
  873.             /* Preferences kopieren. */
  874.  
  875.         GetPrefs(Prefs,sizeof(struct Preferences));
  876.  
  877.             /* Schattenfarbe in Komponenten aufsplitten. */
  878.  
  879.         Shadow[0] = ((Prefs -> color18 >> 8) & 0xF);
  880.         Shadow[1] = ((Prefs -> color18 >> 4) & 0xF);
  881.         Shadow[2] = ((Prefs -> color18     ) & 0xF);
  882.  
  883.             /* Zeichenfarbe in Komponenten aufsplitten. */
  884.  
  885.         Render[0] = ((Prefs -> color19 >> 8) & 0xF);
  886.         Render[1] = ((Prefs -> color19 >> 4) & 0xF);
  887.         Render[2] = ((Prefs -> color19     ) & 0xF);
  888.  
  889.             /* Puffer wieder freigeben. */
  890.  
  891.         FreeMem(Prefs,sizeof(struct Preferences));
  892.     }
  893. }
  894.  
  895.     /* main() :
  896.      *
  897.      *    Endlich! Nach soviel Vorbereitung nun schließlich
  898.      *    das Hauptprogramm.
  899.      */
  900.  
  901. void
  902. main()
  903. {
  904.         /* Fall MouseClock ein zweites Mal gestartet
  905.          * wird, teilt es dem schon laufenden Task mit, daß
  906.          * er sich entfernen soll. Diese Nachricht wird mit
  907.          * den folgenden Strukturen verschickt.
  908.          */
  909.  
  910.     struct MsgPort *ReplyPort;
  911.     struct Message WakeUp,*Terminate;
  912.  
  913.     struct DMSFragment *DMS = (struct DMSFragment *)FindPort("DMouse");
  914.     LONG MouseTimeout = 4;
  915.  
  916.         /* Zeichenpuffer, um die gewünschten Daten auf zwei
  917.          * Sprites verteilen zu können.
  918.          */
  919.  
  920.     char DateBuff1[5],DateBuff2[5];
  921.     char TimeBuff1[5],TimeBuff2[5];
  922.     char FastBuff1[5],FastBuff2[5];
  923.     char ChipBuff1[5],ChipBuff2[5];
  924.     char *ptr;
  925.  
  926.         /* Letzte Position des Mauszeigers. */
  927.  
  928.     LONG LastX = 0,LastY = 0;
  929.  
  930.         /* Wie oft lief die Prüfschleife schon durch, ohne
  931.          * daß sich der Mauszeiger bewegte und wie
  932.          * oft lief sie schon durch, ohne daß der Inhalt der
  933.          * Sprites verändert werden mußte?
  934.          */
  935.  
  936.     LONG MoveCount = 0,i;
  937.  
  938.         /* Eingabeart, schon wieder so eine Erfindung von =RJ=,
  939.          * was meint ihr, welchen Ärger ich mit ProSuite
  940.          * hatte! Ich habe fast alles noch einmal schreiben
  941.          * müssen, da die Hälfte der Includes zu nichts zu
  942.          * gebrauchen war!
  943.          */
  944.  
  945.     ULONG Class;
  946.  
  947.         /* Falls schon eine MouseClock läuft, wird ihr
  948.          * eine Nachricht zugesandt, die sie dazu veranlassen
  949.          * soll, sich zu entfernen.
  950.          */
  951.  
  952.     if(MouseClockPort = (struct MsgPort *)FindPort("MouseClockPort",0))
  953.     {
  954.             /* Die Rückantwort soll hier eingehen. */
  955.  
  956.         if(!(ReplyPort = (struct MsgPort *)CreatePort(NULL,0)))
  957.             exit(20);
  958.  
  959.             /* Nachricht initialisieren. */
  960.  
  961.         WakeUp . mn_Node . ln_Type    = NT_MESSAGE;
  962.         WakeUp . mn_Length        = sizeof(struct Message);
  963.         WakeUp . mn_ReplyPort        = ReplyPort;
  964.  
  965.             /* An den MessagePort schicken und
  966.              * auf Bestätigung warten.
  967.              */
  968.  
  969.         PutMsg(MouseClockPort,&WakeUp);
  970.         Wait(1 << ReplyPort -> mp_SigBit);
  971.  
  972.             /* Rückantwortsport löschen. */
  973.  
  974.         DeletePort(ReplyPort);
  975.  
  976.         exit(0);
  977.     }
  978.  
  979.         /* Alles öffnen und Farben der Sprites anpassen. */
  980.  
  981.     OpenAll();
  982.     AdjustColours();
  983.  
  984.     FOREVER
  985.     {
  986.             /* Sollen wir uns schon entfernen? */
  987.  
  988.         if(Terminate = (struct Message *)GetMsg(MouseClockPort))
  989.         {
  990.             ReplyMsg(Terminate);
  991.             CloseAll(0);
  992.         }
  993.  
  994.         if(DMS)
  995.             if((MouseTimeout = DMS -> MTo - 1) < 0)
  996.                 MouseTimeout = 0;
  997.  
  998.         Class = NULL;
  999.  
  1000.             /* Ist irgendetwas am Fenster passiert? */
  1001.  
  1002.         if(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1003.         {
  1004.             Class = Massage -> Class;
  1005.  
  1006.             ReplyMsg(Massage);
  1007.         }
  1008.  
  1009.             /* Schließgadget gewählt? */
  1010.  
  1011.         if(Class == CLOSEWINDOW)
  1012.             CloseAll(0);
  1013.  
  1014.             /* Die Farben des Mauszeigers könnten sich
  1015.              * geändert haben.
  1016.              */
  1017.  
  1018.         if(Class == NEWPREFS)
  1019.             AdjustColours();
  1020.  
  1021.             /* Das ED-Symbol muß nachgezeichnet werden. */
  1022.  
  1023.         if(Class == REFRESHWINDOW)
  1024.         {
  1025.             BeginRefresh(Window);
  1026.             DrawImage(Window -> RPort,&ClipImage,4,0);
  1027.             EndRefresh(Window,TRUE);
  1028.         }
  1029.  
  1030.             /* Wir wurden aktiviert und melden uns
  1031.              * auch gleich.
  1032.              */
  1033.  
  1034.         if(Class == ACTIVEWINDOW)
  1035.         {
  1036.             PrintIText(Window -> WScreen -> BarLayer -> rp,&AboutTxt[0],4,0);
  1037.             DrawImage(Window -> WScreen -> BarLayer -> rp,&ClipImage,210,0);
  1038.         }
  1039.  
  1040.             /* Wenn sich der Mauszeiger seit fünf
  1041.              * Sekunden nicht bewegt hat, wird die
  1042.              * Anzeige von MouseClock ausgeschaltet.
  1043.              * Bewegt sich der Mauszeiger anschließend
  1044.              * jedoch wieder, werden die Sprites
  1045.              * angeschaltet.
  1046.              */
  1047.  
  1048.         if(CurX != LastX || CurY != LastY)
  1049.         {
  1050.                 /* Sprites wieder anschalten. */
  1051.  
  1052.             if(MoveCount > MouseTimeout)
  1053.             {
  1054.                 GetSprite(&Position1,2);
  1055.                 GetSprite(&Position2,3);
  1056.  
  1057.                 DoPosition = TRUE;
  1058.             }
  1059.  
  1060.             MoveCount = 0;
  1061.         }
  1062.         else
  1063.         {
  1064.             if((++MoveCount) >= MouseTimeout)
  1065.             {
  1066.                     /* Sprites ausschalten. */
  1067.  
  1068.                 if(MoveCount == MouseTimeout)
  1069.                 {
  1070.                     DoPosition = FALSE;
  1071.  
  1072.                     WaitTOF();
  1073.                     WaitTOF();
  1074.  
  1075.                     FreeSprite(2);
  1076.                     FreeSprite(3);
  1077.                 }
  1078.  
  1079.                 continue;
  1080.             }
  1081.         }
  1082.  
  1083.             /* Nur um sicherzugehen, daß wir es überhaupt
  1084.              * bemerken, wenn sich der Mauszeiger nicht
  1085.              * bewegt hat.
  1086.              */
  1087.  
  1088.         LastX = CurX;
  1089.         LastY = CurY;
  1090.  
  1091.             /* Datum abfragen und aufspalten. */
  1092.  
  1093.         ptr = WhichDate();
  1094.  
  1095.         for(i = 0 ; i < 4 ; i++)
  1096.         {
  1097.             DateBuff1[i] = ptr[i];
  1098.             DateBuff2[i] = ptr[i + 4];
  1099.         }
  1100.  
  1101.         DateBuff1[4] = DateBuff2[4] = 0;
  1102.  
  1103.             /* Zeit abfragen und aufspalten. */
  1104.  
  1105.         ptr = WhichTime();
  1106.  
  1107.         for(i = 0 ; i < 4 ; i++)
  1108.         {
  1109.             TimeBuff1[i] = ptr[i];
  1110.             TimeBuff2[i] = ptr[i + 4];
  1111.         }
  1112.  
  1113.         TimeBuff1[4] = TimeBuff2[4] = 0;
  1114.  
  1115.             /* Chip-Ram abfragen und aufspalten. */
  1116.  
  1117.         ptr = WhichMem(MEMF_CHIP);
  1118.  
  1119.         for(i = 0 ; i < 4 ; i++)
  1120.         {
  1121.             ChipBuff1[i] = ptr[i];
  1122.             ChipBuff2[i] = ptr[i + 4];
  1123.         }
  1124.  
  1125.         ChipBuff1[4] = ChipBuff2[4] = 0;
  1126.  
  1127.             /* Fast-Ram abfragen und aufspalten. */
  1128.  
  1129.         ptr = WhichMem(MEMF_FAST);
  1130.  
  1131.         for(i = 0 ; i < 4 ; i++)
  1132.         {
  1133.             FastBuff1[i] = ptr[i];
  1134.             FastBuff2[i] = ptr[i + 4];
  1135.         }
  1136.  
  1137.         FastBuff1[4] = FastBuff2[4] = 0;
  1138.  
  1139.             /* Bitmap löschen und linkes
  1140.              * Sprite erzeugen.
  1141.              */
  1142.  
  1143.         SetRast(&PointerRPort,0);
  1144.  
  1145.         DoPtrTxt(10,TimeBuff2);
  1146.         DoPtrTxt(22,DateBuff2);
  1147.         DoPtrTxt(34,ChipBuff2);
  1148.         DoPtrTxt(46,FastBuff2);
  1149.  
  1150.         MapToSprite(Pointer2Data,&PointerBMap);
  1151.  
  1152.             /* Bitmap löschen und rechtes
  1153.              * Sprite erzeugen.
  1154.              */
  1155.  
  1156.         SetRast(&PointerRPort,0);
  1157.  
  1158.         DoPtrTxt(4,"TIME");
  1159.         DoPtrTxt(10,TimeBuff1);
  1160.  
  1161.         DoPtrTxt(16,"DATE");
  1162.         DoPtrTxt(22,DateBuff1);
  1163.  
  1164.         DoPtrTxt(28,"CHIP");
  1165.         DoPtrTxt(34,ChipBuff1);
  1166.  
  1167.         DoPtrTxt(40,"FAST");
  1168.         DoPtrTxt(46,FastBuff1);
  1169.  
  1170.         MapToSprite(Pointer1Data,&PointerBMap);
  1171.  
  1172.             /* Neue Sprites anzeigen. */
  1173.  
  1174.         ChangeSprite(NULL,&Position1,Pointer1Data);
  1175.         ChangeSprite(NULL,&Position2,Pointer2Data);
  1176.  
  1177.             /* Eine Zeitperiode warten. */
  1178.  
  1179.         WaitTime(1,0);
  1180.     }
  1181. }
  1182.