#define VERSION "1.11 (14.04.94)"
/***************************************************************************
*                                  *                                       *
* Programm: TolleUhr               * Version: s.o.                         *
*                                  *                                       *
****************************************************************************
*                                                                          *
* Dieses Programm ist Public-Domain, d.h. wer immer Lust dazu hat, darf    *
* dieses Programm kopieren, umschreiben, usw., vorausgesetzt:              *
*                                                                          *
* 1. Die Autorenliste bleibt voll erhalten. (auch in About-Requestern)     *
* 2. Wer etwas am Programm verbricht, muß sich auch dazuschreiben.         *
*                                                                          *
* Es wird keine Haftung für Schäden irgendwelcher Art übernommen.          *
*                                                                          *
* Autor: Matthias Fleischer  Adlerstraße 30 7302 Ostfildern 2              *
*        (fleischr@izfm.uni-stuttgart.de)                                  *
*        .                                                                 *
*        .(Auf Paul, schaff was !)                                         *
*                                                                          *
* changes: - NewLookMenus with Kick3.0+                                    *
*          - consequent use of kickstart 2.0+ functions                    *
*            ( AllocMem->AllocVec,AllocDosObject )                         *
*          - bugfixed ( area-table was to small )                          *
*          - openlibs() && closelibs() removed, now automatically opened   *
*            and closed by startup code                                    *
*          - some new local vars to enable better optimization             *
*          - compiled with inline headers using gcc2.3.3 (still the best!) *
*          - two versions: plain 68000 && 68020+                           *
*                                                                          *
*           ^ by: gnikl@informatik.uni-rostock.de                          *
*                                                                          *
* Soll mit Inline && -fbaserel compiliert werden,muessen AutoRequest sowie *
* CreateGadgetA im jeweiligen inline-file auskommentiert werden !!!        *
*                                                                          *
***************************************************************************/

/**** includes ****/

#include <dos/dos.h>
#include <dos/exall.h>
#include <dos/rdargs.h>
#include <exec/memory.h>
#include <devices/audio.h>
#include <graphics/scale.h>
#include <graphics/graphint.h>
#include <graphics/gfxmacros.h>
#include <libraries/gadtools.h>
#include <intuition/cghooks.h>
#include <intuition/classes.h>
#include <intuition/gadgetclass.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>
#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#ifndef INLINE
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/icon_protos.h>
#include <clib/graphics_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/intuition_protos.h>
#else
#include <inline/dos.h>
#include <inline/exec.h>
#include <inline/alib.h>
#include <inline/icon.h>
#include <inline/graphics.h>
#include <inline/gadtools.h>
#include <inline/intuition.h>
#endif

/* magic defines */

#define exit _exit
#define main _main
#define WbMsg _WBenchMsg

/* externe Symbole */

extern void exit(int);
extern struct WBStartup *WbMsg;

/**** Sonstiges ****/

char version[]="$VER:TolleUhr "VERSION" by M.Fleischer and G.Nikl in 1993/94";
#define aboutstring (version+5)

typedef struct IORequest *iorequest;
typedef struct timerequest *iotime;
typedef struct IOAudio *ioaudio;

/**** Eigene Prototypen ****/

int main();
void mergetooltypes(struct WBStartup *args);
void parsecliargs(char *argstring,int laenge);
int xtod(int a);
void setargs(void);
void setpattern(void);
void readstr(char *dest,char *sorc,int n);
int nexttick(void);
void openall(void);
void closeall(int retval);
void newsize1(void); /* Löscht BitPlanes */
void newsize2(void); /* Holt BitPlanes */
void zifferblatt (void);
void rahmen(void);
void zeichnen(void);
void zeiger(ULONG winkel,int lfactor,int offset,int apen,int open);
void getcolor(UBYTE *color);
void setalarm(void);
void cdtoicon(struct WBStartup *args);
void savecli();
void saveprefs(char *myname);
void setstr(char *dest,UBYTE *sourc,int n);
int dtox(int a);
void testifalarm(void);
void starttune(UWORD *tune);
void playnote(void);
void endtune(void);
struct Window *creatertrequest
( struct TagItem windowtags[],int anzgadgets,struct TagItem *gadgettags[],
  struct NewGadget gadgets[],ULONG edge[][3],struct Gadget **glistpointer);

/**** Ressourcen müssen global sein (wegen cleanup) ****/

struct Screen *pubscreen=NULL; /* Den blocken wir */
struct Window *mywindow=NULL; /* 1 Fenster */
struct IntuiMessage *msg; /* Für Gadgets */
struct Menu *menus=NULL;
APTR visi=NULL;
struct MsgPort *tport=NULL; /* Timer */
iotime treq=NULL;
int notime=1;
int timesent=0;
char *string=NULL; /* für ToolTypes */
struct DiskObject *dobj=NULL;
APTR buf=NULL; /* BitPlane für Area-Befehle */
struct MsgPort *audport=NULL; /* Alles für audio.device */
ioaudio audreq[2]={ NULL,NULL };
int noaudio=1; /* device geöffnet ? */
int nosound=1; /* Soundkanal geholt ? */
int audsent[2]={ 0,0 }; /* Sound gespielt ? */
BYTE *waveform=NULL;
LONG oldpri; /* Task-Priority */
int changedpri=0;

/**** Voreinstellungen ****/

long links =50;
long oben  =50;
long breite=108;
long hoehe =54;
int sekunden=0;
int oval=0;
int zeigen=1;
int zeigertyp=2;
int zeigerbreite=2;
int schatten=0;
int rahmenanz=3;
UBYTE pens[]={ 2,0,2,0,2,1,2,2,2,2,0,1,2,3 };
             /* sec,mina,mino,stda,stdo,shdw,12,1/4,1/12,1/60,b0,b1,b2,b3 */
UBYTE must[]={ 0,0,0,0 };
ULONG almin=0,alstd=12; /* Alarmzeit */
int smarthour=0;
int alarm=0;
int chime=0;

/**** Globale Variablen ****/

ULONG maskx,masky;
UWORD muster[8][2];
int doublex,doubley;
long xoffset,yoffset;
long boleft,botop,breit2,hoehe2;
long hires,interlace,active=0;
ULONG std,min,sec;
long redrawx1,redrawx2,redrawy1,redrawy2; /* Gezeichneter Bereich bezogen
                                             auf Fensterkoordinaten */
struct IntuiText about=
{ 0,0,JAM1,15,5,NULL,aboutstring,NULL }, /* About-Text */
                 oktext=
{ 0,0,JAM1,6,3,NULL,"OK",NULL }; /* OK-Text */
struct TagItem notags[]={ TAG_DONE }; /* Leeres TagItem-Feld */
struct RastPort *rport1; /* Fenster */
struct BitMap abitmap; /* Buffer */
struct RastPort rport2;
struct TmpRas temp; /* Für Area-Befehle */
struct AreaInfo info;
SHORT table[13]; /* Für Area-Befehle */
UWORD *playtune;
struct TextAttr topaz={ "topaz.font",8,FS_NORMAL,FPF_ROMFONT };
ULONG ergebnis[20]={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

/**** Tabellen ****/

long handwidth[]={ 4000,3250,2500,1750,1000 };

long sizes[][4]={ 0,0,3,2, -3,0,3,2, -3,-2,3,2, 0,2,0,-4 }; /* Für Gadgets */

struct Gadget gadgets[]={
{ &gadgets[1],0,0,1,1,GADGHNONE,
  0,CLOSE,NULL,NULL,NULL,0,NULL,0,NULL },         /* Schließ-Gadget */
{ &gadgets[2],0,0,1,1,GADGHNONE|GRELRIGHT,
  0,WUPFRONT,NULL,NULL,NULL,0,NULL,0,NULL },      /* Tiefen-Gadget */
{ &gadgets[3],0,0,1,1,GADGHNONE|GRELRIGHT|GRELBOTTOM,
  0,SIZING,NULL,NULL,NULL,0,NULL,0,NULL },        /* Größen-Gadget */
{ NULL       ,0,0,1,1,GADGHNONE|GRELWIDTH|GRELHEIGHT,
  0,WDRAGGING,NULL,NULL,NULL,0,NULL,0,NULL } };   /* Zieh-Gadget */

struct TagItem windowtags[]=
{ WA_Left,0,WA_Top,0,WA_Width,0,WA_Height,0, /* Fensterkoordinaten (s.u.) */
  WA_PubScreen,0, /* kommt später rein */
  WA_MinWidth,10,WA_MinHeight,10,WA_MaxWidth,-1,WA_MaxHeight,-1,
  WA_Gadgets,(ULONG)gadgets,                 /* Liste von Gadgets */
  WA_Borderless,1,                           /* Rahmen mach ich selber */
  WA_SimpleRefresh,1,                        /* Spart CHIP-MEM */
  WA_NewLookMenus,1,
  WA_IDCMP,NEWSIZE|CLOSEWINDOW|MENUPICK|REFRESHWINDOW|
           ACTIVEWINDOW|INACTIVEWINDOW,          /* Message-Port */
  WA_ScreenTitle,(ULONG)aboutstring,
  TAG_DONE };

struct TagItem menutags[]=
{ GTMN_NewLookMenus,TRUE,TAG_DONE };

struct NewMenu menulist[]= /* Liste von Menus */
{ { NM_TITLE,"Project",  NULL,0,0,NULL },
  { NM_ITEM, "About",    NULL,0,0,NULL },
  { NM_ITEM, "Save Prefs",NULL,0,0,NULL },
  { NM_ITEM, "Quit",     NULL,0,0,NULL },
  { NM_TITLE,"Settings", NULL,0,0,NULL },
  { NM_ITEM, "Seconds",  NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_ITEM, "Oval",     NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_ITEM, "Show",     NULL,0,0,NULL },
  { NM_SUB,  "Minutes",  NULL,CHECKIT,2|4|8|16,NULL },
  { NM_SUB,  "Hours",    NULL,CHECKIT,1|4|8|16,NULL },
  { NM_SUB,  "Quarter",  NULL,CHECKIT,1|2|8|16,NULL },
  { NM_SUB,  "One",      NULL,CHECKIT,1|2|4|16,NULL },
  { NM_SUB,  "None",     NULL,CHECKIT,1|2|4| 8,NULL },
  { NM_ITEM, "Hands",    NULL,0,0,NULL },
  { NM_SUB,  "Line",     NULL,CHECKIT,2|4|8,NULL },
  { NM_SUB,  "Triangle", NULL,CHECKIT,1|4|8,NULL },
  { NM_SUB,  "Rhombus",  NULL,CHECKIT,1|2|8,NULL },
  { NM_SUB,  "Rectangle",NULL,CHECKIT,1|2|4,NULL },
  { NM_SUB,  NM_BARLABEL,NULL,0,0,NULL },
  { NM_SUB,  "Very Thin",NULL,CHECKIT,64|128|256|512,NULL },
  { NM_SUB,  "Thin",     NULL,CHECKIT,32|128|256|512,NULL },
  { NM_SUB,  "Normal",   NULL,CHECKIT,32|64|256|512,NULL },
  { NM_SUB,  "Thick",    NULL,CHECKIT,32|64|128|512,NULL },
  { NM_SUB,  "Very Thick",NULL,CHECKIT,32|64|128|256,NULL },
  { NM_ITEM, "Shadow",   NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_ITEM, "Border",   NULL,0,0,NULL },
  { NM_SUB,  "None",     NULL,CHECKIT,2|4,NULL },
  { NM_SUB,  "Single",   NULL,CHECKIT,1|4,NULL },
  { NM_SUB,  "Double",   NULL,CHECKIT,1|2,NULL },
  { NM_SUB,  NM_BARLABEL,NULL,0,0,NULL },
  { NM_SUB,  "Hires",    NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_SUB,  "Interlace",NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_ITEM, "Chime",    NULL,0,0,NULL },
  { NM_SUB,  "None",     NULL,CHECKIT,2|4,NULL },
  { NM_SUB,  "Hours",    NULL,CHECKIT,1|4,NULL },
  { NM_SUB,  "Quarter",  NULL,CHECKIT,1|2,NULL },
  { NM_SUB,  NM_BARLABEL,NULL,0,0,NULL },
  { NM_SUB,  "Smart",    NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_ITEM, "Alarm",    NULL,0,0,NULL },
  { NM_SUB,  "Set",      NULL,0,0,NULL },
  { NM_SUB,  "On",       NULL,CHECKIT|MENUTOGGLE,0,NULL },
  { NM_TITLE,"Colors",   NULL,0,0,NULL }, /* Colours Menu */
  { NM_ITEM, "Seconds",  NULL,0,0,NULL },
  { NM_ITEM, "Min. APen",NULL,0,0,NULL },
  { NM_ITEM, "Min. OPen",NULL,0,0,NULL },
  { NM_ITEM, "Hour APen",NULL,0,0,NULL },
  { NM_ITEM, "Hour OPen",NULL,0,0,NULL },
  { NM_ITEM, "Shadow",   NULL,0,0,NULL },
  { NM_ITEM, "12",       NULL,0,0,NULL },
  { NM_ITEM, "Quarter",  NULL,0,0,NULL },
  { NM_ITEM, "Hours",    NULL,0,0,NULL },
  { NM_ITEM, "Minutes",  NULL,0,0,NULL },
  { NM_ITEM, "Border 0", NULL,0,0,NULL },
  { NM_ITEM, "Border 1", NULL,0,0,NULL },
  { NM_ITEM, "Border 2", NULL,0,0,NULL },
  { NM_ITEM, "Border 3", NULL,0,0,NULL },
  { NM_TITLE,"Pattern",  NULL,0,0,NULL },
  { NM_ITEM, "Color 0",  NULL,0,0,NULL },
  { NM_ITEM, "Color 1",  NULL,0,0,NULL },
  { NM_ITEM, "Color 2",  NULL,0,0,NULL },
  { NM_ITEM, "Color 3",  NULL,0,0,NULL },
  { NM_END,NULL,NULL,0,0,NULL } };

BYTE sinus[]= /* sinus-Tabelle */
{ 0,13,26,39,52,64,75,85,94,103,110,116,121,124,126,
  127,126,124,121,116,110,103,94,85,75,64,52,39,26,13,
  0,-13,-26,-39,-52,-64,-75,-85,-94,-103,-110,-116,-121,-124,-126,
  -127,-126,-124,-121,-116,-110,-103,-94,-85,-75,-64,-52,-39,-26,-13 },
     cosinus[]= /* cosinus-Tabelle */
{ 127,126,124,121,116,110,103,94,85,75,64,52,39,26,13,
  0,-13,-26,-39,-52,-64,-75,-85,-94,-103,-110,-116,-121,-124,-126,
  -127,-126,-124,-121,-116,-110,-103,-94,-85,-75,-64,-52,-39,-26,-13,
  0,13,26,39,52,64,75,85,94,103,110,116,121,124,126 };

BYTE srect[]= /* Für rechteckiges Zifferblatt */
{ 0,13,27,41,57,73,92,111,124,127,127,127,127,127,127,
  127,127,127,127,127,127,127,124,111,92,73,57,41,27,13,
  0,-13,-27,-41,-57,-73,-92,-111,-124,-127,-127,-127,-127,-127,-127,
  -127,-127,-127,-127,-127,-127,-127,-124,-111,-92,-73,-57,-41,-27,-13 },
     crect[]=
{ 127,127,127,127,127,127,127,124,111,92,73,57,41,27,13,
  0,-13,-27,-41,-57,-73,-92,-111,-124,-127,-127,-127,-127,-127,-127,
  -127,-127,-127,-127,-127,-127,-127,-124,-111,-92,-73,-57,-41,-27,-13,
  0,13,27,41,57,73,92,111,124,127,127,127,127,127,127 };

UBYTE pent[]={ 6,8,8,7,8,8,7,8,8,7,8,8 }; /* Pen-Tabelle f. Zifferblatt */

BYTE dx1[]= /* Daten für Zifferblatt */
{ -2, 2, 1,-2, 1, 2,-2,-2,-1,-2,-1,-2 },
     dy1[]=
{ -4,-1,-2,-2, 2, 1,-2, 1, 2,-2,-2,-1 },
     dx2[]=
{  4,-2, 1, 4, 1,-2, 4, 2,-1, 4,-1, 2 },
     dy2[]=
{  0, 3, 2, 0,-2,-3, 0,-3,-2, 0, 2, 3 },
     dx3[]=
{  0,-2,-3, 0,-3,-2, 0, 2, 3, 0, 3, 2 },
     dy3[]=
{  8,-1, 2, 4,-2, 1, 4, 1,-2, 4, 2,-1 },
     dx4[]=
{ -4, 2,-1,-4,-1, 2,-4,-2, 1,-4, 1,-2 },
     dy4[]=
{  0,-3,-2, 0, 2, 3, 0, 3, 2, 0,-2,-3 };

  /* Requester 1 */
struct TagItem window2tags[]= /* Palette-Requester */
{ WA_Gadgets,0, /* kommen später rein */
  WA_PubScreen,0, /* das auch */
  WA_Left,100,WA_Top,100,WA_InnerWidth,144,WA_InnerHeight,72, /* Fensterkoordinaten */
  WA_IDCMP,CLOSEWINDOW|PALETTEIDCMP,         /* Message-Port */
  WA_Title,(ULONG)"Choose one:",
  WA_ScreenTitle,(ULONG)aboutstring,
  WA_DepthGadget,1,WA_CloseGadget,1,WA_DragBar,1,WA_Activate,1,
  TAG_DONE };

ULONG window2goff[][3]=
{ 4,2,PALETTE_KIND };

struct NewGadget window2gad[]=
{ 0,0,136,68,NULL,NULL,0,0,NULL,0 };

struct TagItem window2gadtags1[]=
{ GTPA_Depth,0,TAG_DONE };

struct TagItem *window2gadtags[]=
{ window2gadtags1 };

  /* Requester 2 */
struct TagItem window3tags[]= /* Alarmzeit-Requester */
{ WA_Gadgets,0, /* kommen später rein */
  WA_PubScreen,0, /* das auch */
  WA_Left,100,WA_Top,100,WA_InnerWidth,144,WA_InnerHeight,72,
  WA_IDCMP,CLOSEWINDOW|BUTTONIDCMP|SLIDERIDCMP,
  WA_Title,(ULONG)"Alarm",
  WA_ScreenTitle,(ULONG)aboutstring,
  WA_DepthGadget,1,WA_CloseGadget,1,WA_DragBar,1,WA_Activate,1,
  TAG_DONE };

ULONG window3goff[][3]=
{ { 42,15,SLIDER_KIND },
  { 82,15,SLIDER_KIND },
  {  2,58,BUTTON_KIND },
  { 76,58,BUTTON_KIND } };

struct NewGadget window3gad[]=
{ { 0,0,20,39,NULL,    &topaz,1,0,NULL,0 },
  { 0,0,20,39,NULL,    &topaz,2,0,NULL,0 },
  { 0,0,66,12,"Use",   &topaz,3,0,NULL,0 },
  { 0,0,66,12,"Cancel",&topaz,4,0,NULL,0 } };

struct TagItem window3gadtags1[]=
{ GTSL_Level,1,PGA_Freedom,LORIENT_VERT,GTSL_LevelPlace,PLACETEXT_ABOVE,
  GTSL_MaxLevelLen,10,GTSL_Min,1,GTSL_Max,12,GTSL_LevelFormat,
  (ULONG)"%2ld",GA_RelVerify,1,TAG_DONE },
               window3gadtags2[]=
{ GTSL_Level,0,PGA_Freedom,LORIENT_VERT,GTSL_LevelPlace,PLACETEXT_ABOVE,
  GTSL_MaxLevelLen,5,GTSL_Min,0,GTSL_Max,59,GTSL_LevelFormat,
  (ULONG)"%02ld",GA_RelVerify,1,TAG_DONE };

struct TagItem *window3gadtags[]=
{ window3gadtags1,window3gadtags2,notags,notags };

UBYTE camap[]={ 1,2,4,8 }; /* Sound Channel Allocation Map */

UWORD alarmtune[]={ 800,800,800,800,800,800,800,1600,
                    800,800,800,800,800,800,800,1600,
                    800,800,800,800,800,800,800,1600,
                    800,800,800,800,800,800,800,1600,
                    800,800,800,800,800,800,800,4,0 };

UWORD hourtune[]={ 800,1600,800,1600,800,1600,800,1600,
                   800,1600,800,1600,800,1600,800,1600,
                   800,1600,800,1600,800,1600,800,4,0 };

UWORD quartertune[]={ 400,400,400,400,400,4,0 };

char pattern[]=
"/M,TOP/N,LEFT/N,WIDTH/N,HEIGHT/N,SECONDS/S,PATTERN/K,OVAL/S,SHADOW/S,"
"SHOWFACE/N,HANDTYPE/N,HANDWIDTH/N,DRAWPENS/K,BORDERTYPE/N,CHIME/N,"
"PUBSCREEN/K,TASKPRI/N";

char *tooltypes[]={
"TOP","LEFT","WIDTH","HEIGHT","SHOWFACE","HANDTYPE","HANDWIDTH","BORDERTYPE",
"CHIME","SECONDS","OVAL","SHADOW","DRAWPENS","PATTERN" };

int main()
{ ULONG class;
  UWORD code;
  ULONG signals;
  UWORD check;
  struct MenuItem *item,*item2;
  if (WbMsg) /* Start von Workbench */
    mergetooltypes(WbMsg);
  else
    parsecliargs(NULL,0);
  openall();

  nexttick();
  rahmen();
  zifferblatt ();
  zeichnen ();
  for (;;)
  { signals=Wait(SIGBREAKF_CTRL_C| /* User-Break */
                 1<<tport->mp_SigBit| /* Timer-Signal */
                 1<<audport->mp_SigBit| /* Audio-Device */
                 1<<mywindow->UserPort->mp_SigBit); /* IDCMP-Signal */
    if (GetMsg(tport)) /* Timer-Signal ? */
    { if (nexttick())
      { zifferblatt();
        testifalarm(); }
      zeichnen(); }
    if (GetMsg(audport)) /* Audio */
      playnote();
    while (msg=GT_GetIMsg(mywindow->UserPort))
    { class=msg->Class;
      code=msg->Code;
      GT_ReplyIMsg(msg);
      switch (class)
      { case NEWSIZE:
          newsize1();
          newsize2();
          rahmen();
          zifferblatt ();
          zeichnen ();
          break;
        case REFRESHWINDOW:
          redrawx1=boleft;
          redrawy1=botop;
          redrawx2=boleft+breit2-1;
          redrawy2=botop +hoehe2-1;
          BeginRefresh(mywindow);
          rahmen();
          zeichnen();
          EndRefresh(mywindow,TRUE);
          break;
        case MENUPICK:
          while (code!=MENUNULL)
          { if (!(item=ItemAddress(menus,code)))
              closeall(RETURN_FAIL);
            check=item->Flags&CHECKED;
            switch (code)
            { case FULLMENUNUM(0,0,NOSUB): /* About */
                AutoRequest(NULL,&about,NULL,&oktext,0,0,0,0);
                break;
              case FULLMENUNUM(0,1,NOSUB): /* Save Prefs */
                if (WbMsg)
                  cdtoicon(WbMsg); /* Von Workbench */
                else
                  savecli(); /* Von CLI */
                break;
              case FULLMENUNUM(0,2,NOSUB): /* Quit */
                closeall(RETURN_OK);
              case FULLMENUNUM(1,0,NOSUB): /* Menu Seconds ausgewählt */
                sekunden=check;
                if (timesent)
                { AbortIO((iorequest)treq);
                  WaitIO((iorequest)treq);
                  timesent=0; }
                nexttick();
                break;
              case FULLMENUNUM(1,1,NOSUB): /* oval umschalten */
                oval=check;
                break;
              case FULLMENUNUM(1,2,0): /* zifferblatt */
              case FULLMENUNUM(1,2,1):
              case FULLMENUNUM(1,2,2):
              case FULLMENUNUM(1,2,3):
              case FULLMENUNUM(1,2,4):
                if (check)
                  zeigen=SUBNUM(code);
                break;
              case FULLMENUNUM(1,3,0): /* zeiger */
              case FULLMENUNUM(1,3,1):
              case FULLMENUNUM(1,3,2):
              case FULLMENUNUM(1,3,3):
                if (check)
                  zeigertyp=SUBNUM(code);
                break;
              case FULLMENUNUM(1,3,5): /* zeigerbreite */
              case FULLMENUNUM(1,3,6):
              case FULLMENUNUM(1,3,7):
              case FULLMENUNUM(1,3,8):
              case FULLMENUNUM(1,3,9):
                if (check)
                  zeigerbreite=SUBNUM(code)-5;
                break;
              case FULLMENUNUM(1,4,NOSUB): /* Shadow */
                schatten=check;
                break;
              case FULLMENUNUM(1,5,0): /* Rahmen */
              case FULLMENUNUM(1,5,1):
              case FULLMENUNUM(1,5,2):
                if (check)
                  rahmenanz=SUBNUM(code);
                break;
              case FULLMENUNUM(1,5,4):
                hires=check;
                break;
              case FULLMENUNUM(1,5,5):
                interlace=check;
                break;
              case FULLMENUNUM(1,6,0): /* Chime */
              case FULLMENUNUM(1,6,1):
              case FULLMENUNUM(1,6,2):
                if (check)
                  chime=SUBNUM(code);
                break;
              case FULLMENUNUM(1,6,4):
                smarthour=check;
                break;
              case FULLMENUNUM(1,7,0): /* Alarm set */
                setalarm();
                item2=ItemAddress(menus,FULLMENUNUM(1,7,1));
                ClearMenuStrip(mywindow); /* Menu entfernen */
                item2->Flags&=~CHECKED;    /* Flags anpassen */
                if (alarm)
                  item2->Flags|=CHECKED;
                ResetMenuStrip(mywindow,menus); /* Menu wieder einfügen */
                break;
              case FULLMENUNUM(1,7,1):
                alarm=check;
                break;
              default:
                if (MENUNUM(code)==2)
                { getcolor(&pens[ITEMNUM(code)]);
                  break; }
                if (MENUNUM(code)==3)
                { getcolor(&must[ITEMNUM(code)]);
                  setpattern();
                  break; }
                break;
            } /* switch menus */
            code=item->NextSelect;
          } /* while */
          newsize1(); /* Zwar manchmal unnötig, aber kurz */
          newsize2();
          rahmen();
          zifferblatt();
          zeichnen();
          break;
        case ACTIVEWINDOW:
          active=1;
          rahmen();
          break;
        case INACTIVEWINDOW:
          active=0;
          rahmen();
          break;
        case CLOSEWINDOW:
          closeall(RETURN_OK);
      } /* switch*/
    } /* if */
    if (signals&SIGBREAKF_CTRL_C) /* User-Break */
      closeall(RETURN_WARN);
  } /* for */
} /* main */

void mergetooltypes(struct WBStartup *args)
{ int i,k;
  BPTR oldlock;
  char *newmem;
  char **ttypes;
  ULONG strln=1;

  if (!args->sm_ArgList) /* Was da wohl für eine Arglist dahintersteckt ? */
    return;
  oldlock=CurrentDir(args->sm_ArgList->wa_Lock); /* CD */
  dobj=GetDiskObjectNew(args->sm_ArgList->wa_Name);
  CurrentDir(oldlock); /* nur zur Sicherheit */
  if (!dobj)
    closeall(RETURN_FAIL);
  ttypes=dobj->do_ToolTypes;
  if (!(string=AllocVec(strln,MEMF_ANY|MEMF_CLEAR)))
    closeall(RETURN_FAIL);
  for (i=0;ttypes[i];i++)
  { for (k=0;ttypes[i][k];k++) /* Länge ermitteln */
      ;
    if (!(newmem=AllocVec(strln+k+1,MEMF_ANY|MEMF_CLEAR))) /* Neuer String */
      closeall(RETURN_FAIL);
    sprintf(newmem,"%s %s",string,ttypes[i]);
    FreeVec(string);
    string=newmem;
    strln+=k+1;
  } /* for */
  FreeDiskObject(dobj);
  dobj=NULL;
  parsecliargs(string,strln-1);
  FreeVec(string);
  string=NULL;
} /* mergetooltypes */

void parsecliargs(char *argstring,int laenge)
{ struct RDArgs *rdarg,*args;
  ULONG *erg;

  if (!(rdarg=AllocDosObject(DOS_RDARGS,NULL)))
    closeall(RETURN_FAIL);
  rdarg->RDA_Source.CS_Buffer=argstring;
  rdarg->RDA_Source.CS_Length=laenge;
  args=ReadArgs(argstring?pattern:&pattern[3],ergebnis,rdarg);
  if (!argstring && !args) /* Fehler in der Kommandozeile */
  {
    FreeDosObject(DOS_RDARGS,rdarg);
    closeall(RETURN_FAIL);
  }
  erg=(argstring?&ergebnis[1]:ergebnis);
  if (erg[0])
    oben  =*(LONG *)erg[0];
  if (erg[1])
    links =*(LONG *)erg[1];
  if (erg[2])
    breite=*(LONG *)erg[2];
  if (erg[3])
    hoehe =*(LONG *)erg[3];
  if (erg[4])
    sekunden=1;
  if (erg[5])
    readstr(must,(char *)erg[5],4);
  if (erg[6])
    oval=1;
  if (erg[7])
    schatten=1;
  if (erg[8])
    zeigen=*(LONG *)erg[8];
  if (erg[9])
    zeigertyp=*(LONG *)erg[9];
  if (erg[10])
    zeigerbreite=*(LONG *)erg[10];
  if (erg[11])
    readstr(pens,(char *)erg[11],14);
  if (erg[12])
    rahmenanz=*(LONG *)erg[12];
  if (erg[13])
    chime=*(LONG *)erg[13];
  pubscreen=LockPubScreen((char *)erg[14]); /* 0 gibt Default-PubScreen */
  if (erg[15])
  { oldpri=SetTaskPri(FindTask(NULL),*(LONG *)erg[15]);
    changedpri=1; }
  FreeArgs(args);
  FreeDosObject(DOS_RDARGS,rdarg);
  setargs();
} /* parsecliargs */

void readstr(char *dest,char *sorc,int n)
{ if (*sorc=='x'||*sorc=='X') /* Hexadezimal */
    while (n-- && *sorc++ && *sorc++)
      *dest++=(xtod(sorc[-1])<<4)+xtod(*sorc);
  else
    while (*sorc && n--) /* Dezimal */
      *dest++=xtod(*sorc++);
} /* readstr */

int xtod(int a)
{ if (a>='0' && a<='9')
    return(a-'0');
  if (a>='a' && a<='f')
    return(a-'a'+10);
  if (a>='A' && a<='F')
    return(a-'A'+10);
  return(0);
} /* xtod */

void setargs(void)
{ if (breite<10)/* Zu schmal ? */
    breite=10;
  if (hoehe<10)
    hoehe=10;
  if (zeigen<0 || zeigen>4)
    zeigen=0;
  if (zeigertyp<0 || zeigertyp>3)
    zeigertyp=0;
  if (zeigerbreite<0 || zeigerbreite>4)
    zeigerbreite=0;
  if (rahmenanz<0 || rahmenanz>5)
    rahmenanz=0;
  if (chime<0 || chime>4)
    chime=0;
  if (chime>2)
  { smarthour=1;
    chime-=2; }
  if (rahmenanz>2)
  { hires=rahmenanz&1;
    interlace=rahmenanz>3;
    rahmenanz=2; }
  setpattern();
} /* setargs */

void setpattern(void)
{ int i,a,b,c,d;
  UBYTE *p1;
  UWORD *p2;

  p1=must; a=*p1++; b=*p1++; c=*p1++; d=*p1;
  if (a==b && c==d) /* nur horizontale Streifen */
    maskx=0xffffffff;
  else
    maskx=0xfffffffe;
  if (a==c && b==d) /* nur vertikale Streifen */
    masky=0xffffffff;
  else
    masky=0xfffffffe;
  p2=muster;
  for (i=0;i<8;i++)
  { *p2=(a&1<<i?0x5555:0)|(b&1<<i?0xaaaa:0); p2++;
    *p2=(c&1<<i?0x5555:0)|(d&1<<i?0xaaaa:0); p2++; }
} /* setpattern */

int nexttick(void)
{ ULONG oldmin;
  treq->tr_node.io_Command=TR_GETSYSTIME;
  DoIO((iorequest)treq);/* Zeit besorgen */
  treq->tr_time.tv_micro=1100000-treq->tr_time.tv_micro;
  sec=treq->tr_time.tv_secs; /* ^ Ein ganz besonders netter Effekt: Das Timerdevice */
  treq->tr_time.tv_secs=(sekunden?0:59-sec%60); /* rundet aktuelle Zeit und Wartezeit ab */
  treq->tr_node.io_Command=TR_ADDREQUEST;
  SendIO((iorequest)treq); /* Und abschicken */
  oldmin=min;
  min=sec/60;
  sec=sec%60;
  std=min/12;
  min=min%60;
  std=std%60;
  timesent=1;
  return (min-oldmin); /* sec==0 ist unzuverlässig bei hoher CPU-Auslastung */
} /* nexttick */

void openall(void)
{ /* Libraries sind schon geöffnet, PubScreen schon blockiert */
  if (!(tport=CreateMsgPort()))/* Port für Timer */
    closeall(RETURN_FAIL);
  if (!(treq=CreateIORequest(tport,sizeof(struct timerequest))))
    closeall(RETURN_FAIL);
  if (notime=OpenDevice(TIMERNAME,UNIT_VBLANK,(iorequest)treq,0))
    closeall(RETURN_FAIL);
  if (!(audport=CreateMsgPort()))/* Replyport für audio.device */
    closeall(RETURN_FAIL);
  if (!(audreq[0]=CreateIORequest(audport,sizeof(struct IOAudio))))
    closeall(RETURN_FAIL);
  if (!(audreq[1]=CreateIORequest(audport,sizeof(struct IOAudio))))
    closeall(RETURN_FAIL);
  if (noaudio=OpenDevice(AUDIONAME,0,(iorequest)audreq[0],0))
    closeall(RETURN_FAIL);
  if (!(waveform=AllocVec(8,MEMF_CHIP|MEMF_CLEAR)))
    closeall(RETURN_FAIL);
  waveform[0]=waveform[2]=127; /* Rechteck */
  waveform[1]=waveform[3]=-128;
  if (!(visi=GetVisualInfoA(pubscreen,NULL)))
    closeall(RETURN_FAIL);
  if (sekunden)
    menulist[5].nm_Flags|=CHECKED;
  if (oval)
    menulist[6].nm_Flags|=CHECKED;
  if (schatten)
    menulist[24].nm_Flags|=CHECKED;
  if (hires)
    menulist[30].nm_Flags|=CHECKED;
  if (interlace)
    menulist[31].nm_Flags|=CHECKED;
  if (smarthour)
    menulist[37].nm_Flags|=CHECKED;
  menulist[8+zeigen].nm_Flags|=CHECKED;
  menulist[14+zeigertyp].nm_Flags|=CHECKED;
  menulist[19+zeigerbreite].nm_Flags|=CHECKED;
  menulist[26+rahmenanz].nm_Flags|=CHECKED;
  menulist[33+chime].nm_Flags|=CHECKED;
  if (!(menus=CreateMenusA(menulist,NULL)))
    closeall(RETURN_FAIL);
  if (!LayoutMenusA(menus,visi,menutags))
    closeall(RETURN_FAIL);
  windowtags[0].ti_Data=links;
  windowtags[1].ti_Data=oben;
  windowtags[2].ti_Data=breite;
  windowtags[3].ti_Data=hoehe;
  windowtags[4].ti_Data=(ULONG)pubscreen;
  if (!(mywindow=OpenWindowTagList(NULL,windowtags)))
    closeall(RETURN_FAIL);
  SetMenuStrip(mywindow,menus);
  rport1=mywindow->RPort;
  SetAPen(rport1,pens[0]);
  newsize2();
} /* openall */

void closeall(int retval) /* Aufräumen */
{ newsize1(); /* Bitmaps löschen */
  if (string)
    FreeVec(string);
  if (dobj)
    FreeDiskObject(dobj);
  if (mywindow) /* Window schließen */
  { ClearMenuStrip(mywindow);
    CloseWindow(mywindow); }
  if (menus)
    FreeMenus(menus);
  if (visi)
    FreeVisualInfo(visi);
  if (pubscreen)
    UnlockPubScreen(NULL,pubscreen);
  if (waveform)
    FreeVec(waveform);
  if (audsent[0])
  { AbortIO((iorequest)audreq[0]); /* Ton abbrechen */
    WaitIO((iorequest)audreq[0]); }
  if (audsent[1])
  { AbortIO((iorequest)audreq[1]); /* Ton abbrechen */
    WaitIO((iorequest)audreq[1]); }
  if (!nosound)
    endtune();
  if (!noaudio)
    CloseDevice((iorequest)audreq[0]);
  if (audreq[1])
    DeleteIORequest(audreq[1]);
  if (audreq[0])
    DeleteIORequest(audreq[0]);
  if (audport)
    DeleteMsgPort(audport);
  if (timesent)
  { AbortIO((iorequest)treq);
    WaitIO((iorequest)treq); }
  if (!notime) /* Timerequest abbrechen */
    CloseDevice((iorequest)treq);
  if (treq)
    DeleteIORequest(treq);
  if (tport)
    DeleteMsgPort(tport);
  if (changedpri)
    SetTaskPri(FindTask(NULL),oldpri);
  exit(retval); /* Fertig */
} /* closeall */

void newsize2(void) /* Holt BitPlanes */
{ int i,k;
  static long gadgsize=-1;
  long newsize;
  boleft=rahmenanz+(hires    ?(rahmenanz==2)<<1:0);
  botop =rahmenanz+(interlace?(rahmenanz==2)<<1:0);
  breite=mywindow->Width;
  hoehe =mywindow->Height;
  breit2=breite-(boleft<<1);
  hoehe2=hoehe -(botop <<1);
  doublex=(maskx==-2&&breit2>12);
  doubley=(masky==-2&&hoehe2>12);
  xoffset=(breit2>50?2:(breit2>25?1:0));
  yoffset=(hoehe2>50?2:(hoehe2>25?1:0));
  newsize=(breite<hoehe?breite/8:hoehe/8);
  if (newsize!=gadgsize)
  { gadgsize=newsize; /* Gadgets müssen in der Größe angepasst werden */
    RemoveGList(mywindow,gadgets,-1);
    for (i=0;i<4;i++)
      for (k=0;k<4;k++) /* Casting ist nicht schön, aber wirksam */
        ((SHORT *)&gadgets[i].LeftEdge)[k]=sizes[i][k]*gadgsize;
    AddGList(mywindow,gadgets,0,4,NULL);
  } /* if */
  InitBitMap(&abitmap,mywindow->WScreen->BitMap.Depth,breit2,hoehe2);
  for (i=0;i<abitmap.Depth;i++)
    if (!(abitmap.Planes[i]=AllocRaster(breit2,hoehe2)))
      closeall(RETURN_FAIL);
  InitRastPort(&rport2);
  rport2.BitMap=&abitmap;
  if (!(buf=AllocRaster(breit2,hoehe2)))
    closeall(RETURN_FAIL);
  rport2.TmpRas=InitTmpRas (&temp,buf,RASSIZE(breit2,hoehe2));
  InitArea (&info,table,5);
  rport2.AreaInfo=(struct AreaInfo *)&info;
} /* newsize2 */

void newsize1(void) /* Löscht BitPlanes */
{ int i;
  if (buf)
  { FreeRaster(buf,breit2,hoehe2);
    buf=NULL; }
  for (i=0;i<abitmap.Depth;i++)
  if (abitmap.Planes[i])
  { FreeRaster(abitmap.Planes[i],breit2,hoehe2);
    abitmap.Planes[i]=NULL; }
} /* newsize1 */

void zifferblatt (void)
{ int i,a,b,c;
  long x0,y0,x,y;

  BNDRYOFF (&rport2); /* Hintergrund */
  SetAPen  (&rport2,-1);
  SetAfPt  (&rport2,*muster,-1);
  RectFill (&rport2,0,0,breit2-1,hoehe2-1);
  SetAfPt  (&rport2,0,0);

  x0=breit2/2;
  y0=hoehe2/2;

  a=(zeigen>1?(zeigen==3?60:15):(zeigen?5:1));
  if (zeigen<4)
    for (i=0;i<60;i+=a)
    { x=x0+((oval?  sinus[i]:srect[i])*breit2/300)&maskx;/* Position des Striches */
      y=y0-((oval?cosinus[i]:crect[i])*hoehe2/300)&masky;
      if (i%5)
      { if (i%5==1)
        { c=pens[9];
          SetAPen(&rport2,c);
          SetOPen(&rport2,c); }
        AreaMove (&rport2,x+breit2/200,y);
        AreaDraw (&rport2,x,y+hoehe2/200);
        AreaDraw (&rport2,x-breit2/200,y);
        AreaDraw (&rport2,x,y-hoehe2/200);
        AreaEnd  (&rport2);
      } else
      { b=i/5;
        c=pens[pent[b]];
        SetAPen(&rport2,c);
        SetOPen(&rport2,c);
        AreaMove (&rport2,x+=breit2*dx1[b]/100,y+=hoehe2*dy1[b]/100);
        AreaDraw (&rport2,x+=breit2*dx2[b]/100,y+=hoehe2*dy2[b]/100);
        AreaDraw (&rport2,x+=breit2*dx3[b]/100,y+=hoehe2*dy3[b]/100);
        AreaDraw (&rport2,x+=breit2*dx4[b]/100,y+=hoehe2*dy4[b]/100);
        AreaEnd  (&rport2);
      } /* if */
    } /* for */
  if (schatten)
  { zeiger(std,440,1,pens[5],pens[5]);
    zeiger(min,300,1,pens[5],pens[5]); }
  zeiger(std,440,0,pens[3],pens[4]);
  zeiger(min,300,0,pens[1],pens[2]);

  redrawx1=boleft;
  redrawy1=botop;
  redrawx2=boleft+breit2-1;
  redrawy2=botop +hoehe2-1;
} /* zifferblatt */

void rahmen(void)
{ if (rahmenanz)
  { SetAPen(rport1,(active&&rahmenanz==1)?pens[12]:pens[11]);
    Move(rport1,1            ,hoehe-1    );
    Draw(rport1,breite-1     ,hoehe-1    );
    Draw(rport1,breite-1     ,1          );
    SetAPen(rport1,(active&&rahmenanz==1)?pens[11]:pens[12]);
    Move(rport1,0,            hoehe-1    );
    Draw(rport1,0,            0          );
    Draw(rport1,breite-1,     0          );
    if (rahmenanz==2)
    { SetAPen(rport1,pens[12]); /* Rahmen */
      Move(rport1,boleft       ,hoehe-botop);
      Draw(rport1,breite-boleft,hoehe-botop);
      Draw(rport1,breite-boleft,botop      );
      SetAPen(rport1,pens[11]);
      Move(rport1,boleft-1     ,hoehe-botop);
      Draw(rport1,boleft-1     ,botop-1    );
      Draw(rport1,breite-boleft,botop-1    );
      SetAPen(rport1,active?pens[13]:pens[10]);
      if (hires)
      { RectFill(rport1,1,1,2,hoehe-2);
        RectFill(rport1,breite-3,1,breite-2,hoehe-2); }
      if (interlace)
      { RectFill(rport1,1,1,breite-2,2);
        RectFill(rport1,1,hoehe-3,breite-2,hoehe-2); }
    } /* if */
  } /* if */
  SetAPen(rport1,pens[0]);
} /* rahmen */

void zeiger(ULONG winkel,int lfactor,int offset,int apen,int open)
{ long x0,y0,x1,y1,x2,y2;
  x0=breit2/2+(offset?xoffset:0);
  y0=hoehe2/2+(offset?yoffset:0);
  x2=sinus  [winkel]*breit2/lfactor;
  y2=cosinus[winkel]*hoehe2/lfactor;
  x1=cosinus[winkel]*breit2/handwidth[zeigerbreite];
  y1=sinus  [winkel]*hoehe2/handwidth[zeigerbreite];
  SetAPen(&rport2,apen);
  SetOPen(&rport2,open);
  switch (zeigertyp)
  { case 0:
      SetAPen(&rport2,open);
      Move (&rport2,x0,y0);
      Draw (&rport2,x0+x2,y0-y2);
      if (doublex)
      { Move (&rport2,1+x0,y0);
        Draw (&rport2,1+x0+x2,y0-y2); }
      if (doubley)
      { Move (&rport2,x0,1+y0);
        Draw (&rport2,x0+x2,1+y0-y2); }
      break;
    case 1:
      AreaMove (&rport2,x0+x2     ,y0-y2     );
      AreaDraw (&rport2,x0+x1-x2/4,y0+y1+y2/4);
      AreaDraw (&rport2,x0-x1-x2/4,y0-y1+y2/4);
      AreaEnd  (&rport2);
      break;
    case 2:
      AreaMove (&rport2,x0+x2  ,y0-y2  );
      AreaDraw (&rport2,x0+x1  ,y0+y1  );
      AreaDraw (&rport2,x0-x2/4,y0+y2/4);
      AreaDraw (&rport2,x0-x1  ,y0-y1  );
      AreaEnd  (&rport2);
      break;
    case 3:
      AreaMove (&rport2,x0+=x2-x1/2,y0-=y2+y1/2);
      AreaDraw (&rport2,x0+=x1     ,y0+=y1     );
      AreaDraw (&rport2,x0-=x2*5/4 ,y0+=y2*5/4 );
      AreaDraw (&rport2,x0-=x1     ,y0-=y1     );
      AreaEnd  (&rport2);
      break;
  } /* switch */
} /* zeiger */

void zeichnen(void)
{ long tmp;
  BltBitMapRastPort(&abitmap,redrawx1-boleft,redrawy1-botop,
                    rport1,redrawx1,redrawy1,
                    redrawx2-redrawx1+1,redrawy2-redrawy1+1,0xc0);
  if (sekunden)
  { redrawx1=breite/2;
    redrawy1=hoehe /2;
    redrawx2=redrawx1+sinus  [sec]*breit2/300;
    redrawy2=redrawy1-cosinus[sec]*hoehe2/300;
    Move(rport1,redrawx1,redrawy1);
    Draw(rport1,redrawx2,redrawy2);
    if (doublex)
    { Move(rport1,1+redrawx1,redrawy1);
      Draw(rport1,1+redrawx2,redrawy2); }
    if (doubley)
    { Move(rport1,redrawx1,1+redrawy1);
      Draw(rport1,redrawx2,1+redrawy2); }
    if (redrawx1>redrawx2)
    { tmp=redrawx1;
      redrawx1=redrawx2;
      redrawx2=tmp; }
    if (redrawy1>redrawy2)
    { tmp=redrawy1;
      redrawy1=redrawy2;
      redrawy2=tmp; }
    if (doublex)
      redrawx2++;
    if (doubley)
      redrawy2++;
  } /* if */
} /* zeichnen */

void getcolor(UBYTE *color)
{ struct Window *window;
  struct Gadget *gadgets;
  struct IntuiMessage *msg;
  window2gadtags1[0].ti_Data=abitmap.Depth;
  if (window=creatertrequest(window2tags,1,window2gadtags,
                             window2gad,window2goff,&gadgets))
  { WaitPort(window->UserPort);
    msg=GT_GetIMsg(window->UserPort);
    if (msg->Class==GADGETUP) /* kann nur das Palette-Gadget sein */
      *color=msg->Code;
    GT_ReplyIMsg(msg);
    CloseWindow(window);
  } /* if */
  FreeGadgets(gadgets);
} /* getcolor */

void setalarm(void)
{ struct Window *window;
  struct Gadget *gadgets;
  struct IntuiMessage *msg;
  ULONG class,st,mi;
  st=window3gadtags1[0].ti_Data=alstd;
  mi=window3gadtags2[0].ti_Data=almin;
  if (window=creatertrequest(window3tags,4,window3gadtags,
                             window3gad,window3goff,&gadgets))
  { do
    { WaitPort(window->UserPort);
      msg=GT_GetIMsg(window->UserPort);
      class=msg->Class;
      if (class==MOUSEMOVE || class==GADGETUP)
      { switch(((struct Gadget *)(msg->IAddress))->GadgetID)
        { case 1:
            st=msg->Code;
            break;
          case 2:
            mi=msg->Code;
            break;
          case 3:
            alstd=st;
            almin=mi;
            alarm=1;
            class=CLOSEWINDOW;
            break;
          case 4:
            class=CLOSEWINDOW;
            break;
        } /* switch */
      } /* if */
      GT_ReplyIMsg(msg);
    } while (class!=CLOSEWINDOW);
    CloseWindow(window);
  } /* if */
  FreeGadgets(gadgets);
} /* getcolor */

struct Window *creatertrequest
( struct TagItem windowtags[],int anzgadgets,struct TagItem *gadgettags[],
  struct NewGadget gadgets[],ULONG edge[][3],struct Gadget **glistpointer)
{ struct Gadget *context;
  struct Window *window;
  int i;
  *glistpointer=NULL;
  if (context=CreateContext(glistpointer))
  { for (i=0;i<anzgadgets;i++)
    { gadgets[i].ng_LeftEdge=edge[i][0]+  mywindow->WScreen->WBorLeft;
      gadgets[i].ng_TopEdge =edge[i][1]+1+mywindow->WScreen->WBorTop+
                                        mywindow->WScreen->RastPort.TxHeight;
      gadgets[i].ng_VisualInfo=visi;
      if (!(context=CreateGadgetA(edge[i][2],context,
                                  &gadgets[i],gadgettags[i])))
        break;
    } /* for */
    if (i==anzgadgets)
    { windowtags[0].ti_Data=(ULONG)*glistpointer;
      windowtags[1].ti_Data=(ULONG)pubscreen;
      if (window=OpenWindowTagList(NULL,windowtags))
      { GT_RefreshWindow(window,NULL);
        return(window); }
    } /* if */
    if (*glistpointer)
      FreeGadgets(*glistpointer);
  } /* if */
  return(NULL);
} /* creatertrequest */

void cdtoicon(struct WBStartup *args)
{ BPTR oldlock;
  if (!args->sm_ArgList) /* Was da wohl für eine Arglist dahintersteckt ? */
    return;
  oldlock=CurrentDir(args->sm_ArgList->wa_Lock); /* CD */
  saveprefs(args->sm_ArgList->wa_Name);
  CurrentDir(oldlock); /* nur zur Sicherheit */
} /* cdtoicon */

void savecli()
{ char *buffer;
  if (buffer=AllocVec(120,MEMF_ANY)) /* should be enough */
  {
    if (GetProgramName(buffer,120))
      saveprefs(buffer);
    FreeVec(buffer);
  }
} /* savecli */

void saveprefs(char *myname)
{ int i,k,a;
  char **ttypes1;
  char **ttypes2;

  if (dobj=GetDiskObjectNew(myname)) /* Tooltypes einlesen */
  { ttypes1=dobj->do_ToolTypes;
    for (i=0;ttypes1[i];i++) /* Tooltypes zählen */
      ;
                          /* sizeof() 4 bytes pro pointer */
    if (ttypes2=AllocVec((i*sizeof(char *)+sizeof(tooltypes)),MEMF_ANY|MEMF_CLEAR))
    { CopyMem(ttypes1,ttypes2,i*sizeof(char *));
      for (i=0;i<sizeof(tooltypes)/sizeof(char *);i++) /* Eigene Tooltypes */
      { if (FindToolType((UBYTE **)ttypes2,tooltypes[i]))        /* entfernen */
        { for (k=1;ttypes2[k]&&FindToolType((UBYTE **)&ttypes2[k],tooltypes[i]);k++)
            ;
          for (k--;ttypes2[k];k++)
            ttypes2[k]=ttypes2[k+1]; }
      } /* for */
      for (i=0;ttypes2[i];i++) /* Tooltypes zählen */
        ;
      for (k=0;k<sizeof(tooltypes)/sizeof(char *);k++) /* je 40 Bytes holen */
        if (!(ttypes2[i+k]=AllocVec(40,MEMF_ANY|MEMF_CLEAR)))
          break;
      if (k==sizeof(tooltypes)/sizeof(char *)) /* Alles Allokiert */
      { a=i;
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[0],mywindow->TopEdge);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[1],mywindow->LeftEdge);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[2],breite);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[3],hoehe);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[4],zeigen);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[5],zeigertyp);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[6],zeigerbreite);
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[7],
          rahmenanz+(rahmenanz==2?(hires?1:0)+(interlace?2:0):0));
        sprintf(ttypes2[a++],"%s=%ld",tooltypes[8],chime+(chime&&smarthour?2:0));
        if (sekunden)
          sprintf(ttypes2[a++],"%s",tooltypes[9]);
        if (oval)
          sprintf(ttypes2[a++],"%s",tooltypes[10]);
        if (schatten)
          sprintf(ttypes2[a++],"%s",tooltypes[11]);
        sprintf(ttypes2[a],"%s=x",tooltypes[12]);
        setstr(&ttypes2[a++][10],pens,14);
        sprintf(ttypes2[a],"%s=x",tooltypes[13]);
        setstr(&ttypes2[a][9],must,4);
        dobj->do_ToolTypes=ttypes2;
        PutDiskObject(myname,dobj);
        dobj->do_ToolTypes=ttypes1;
      } /* if */
      for (;--k>0;) /* Freigeben */
        FreeVec(ttypes2[i+k]);
      FreeVec(ttypes2);
    } /* if */
    FreeDiskObject(dobj);
    dobj=NULL;
  } /* if */
} /* saveprefs */

void setstr(char *dest,UBYTE *sourc,int n)
{ while (n--)
  { *dest++=dtox(*sourc>>4);
    *dest++=dtox(*sourc++&0xf); }
} /* setstr */

int dtox(int a)
{ if (a>9)
    return(a+'A'-10);
  else
    return(a+'0');
} /* dtox */

void testifalarm(void)
{ ULONG st2;
  st2=std/5;
  if (!st2)
    st2=12;
  if (alarm && min==almin && st2==alstd)
    starttune(alarmtune);
  else if (chime && !min)
    starttune(&hourtune[smarthour?24-st2*2:22]);
  else if (chime==2 && (min==15 || min==30 || min==45))
    starttune(&quartertune[6-min/15*2]);
} /* testifalarm */

void starttune(UWORD *tune)
{ ioaudio areq=audreq[0];
  if (!nosound) /* Läuft schon einer */
    return;
  areq->ioa_Request.io_Command=ADCMD_ALLOCATE;
  areq->ioa_Request.io_Message.mn_Node.ln_Pri=90; /* ALARM-Level */
  areq->ioa_Request.io_Flags=ADIOF_NOWAIT;
  areq->ioa_Data=camap;
  areq->ioa_Length=4;
  BeginIO((iorequest)areq);
  if (nosound=WaitIO((iorequest)areq))
    return;
  CopyMem(areq,audreq[1],sizeof(struct IOAudio));
  playtune=tune;
  playnote();
  playnote();
} /* starttune */

void playnote(void)
{ static int requestnr=1;
  ioaudio areq;
  requestnr=!requestnr;
  audsent[requestnr]=0;
  if (!*playtune)
  { if (!audsent[!requestnr]) /* Anderer Request auch zurück ? */
      endtune();
    return; }
  audsent[requestnr]=1; /* Merken */
  areq=audreq[requestnr];
  areq->ioa_Request.io_Command=CMD_WRITE;
  areq->ioa_Request.io_Flags=ADIOF_PERVOL;
  areq->ioa_Data=&waveform[requestnr*4];
  areq->ioa_Length=4;
  areq->ioa_Period=500; /* ekliger Piepton */
  areq->ioa_Volume=64;
  areq->ioa_Cycles=*playtune++;
  BeginIO((iorequest)areq);
} /* playnote */

void endtune(void)
{ ioaudio areq=audreq[0];
  areq->ioa_Request.io_Command=ADCMD_FREE;
  DoIO((iorequest)areq);
  nosound=1;
} /* endtune */
