home *** CD-ROM | disk | FTP | other *** search
- /*
- ** TitleClock - throw up a clock in the top right
- **
- ** Copyright ©1992-94 by Anders Hammarquist, permission granted for
- ** non-commercial use and distribution. See documentation for further
- ** information.
- **
- ** $Id: TitleClock.c,v 3.3 94/02/12 16:08:52 Viking Exp Locker: Viking $
- **
- ** $Revision: 3.3 $
- ** $Date: 94/02/12 16:08:52 $
- **
- */
-
- #define __USE_SYSBASE
-
- #include <dos/datetime.h>
- #include <dos/dos.h>
- #include <exec/memory.h>
- #include <exec/execbase.h>
- #include <exec/devices.h>
- #include <exec/libraries.h>
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
- #include <graphics/gfx.h>
- #include <libraries/commodities.h>
- #include <devices/timer.h>
- #include <proto/exec.h>
- #include <proto/dos.h>
- #include <proto/graphics.h>
- #include <proto/intuition.h>
- #include <proto/icon.h>
- #include <proto/utility.h>
- #include <proto/commodities.h>
- #include <proto/timer.h>
- #include <workbench/workbench.h>
- #include <workbench/startup.h>
- #include "titleclock_protos.h"
-
- #include <libraries/locale.h>
- #include <proto/locale.h>
-
- /* Stuff */
- #define MAXCLOCKLEN 256
- #define CLOCKOFFSET 5 /* Number of pixels between screen depth gadget */
- /* and clock text */
- #define TEMPLATE "UPDATE/N/K,SHOWDATE/S,SHOWDAY/S,SHORTDAY/S,SHOWSECS/S,FORMAT/K,DATEFORMAT/K,PUBSCREEN/K,SCREENPAT/K,FRONTSCREEN/S,DEFSCREEN/S,CX_PRIORITY/N/K"
- enum ArgsEnum
- {
- UPDATE,
- SHOWDATE,
- SHOWDAY,
- SHORTDAY,
- SHOWSECS,
- FORMAT,
- DATEFORMAT,
- PUBSCREEN,
- SCREENPAT,
- FRONTSCREEN,
- DEFSCREEN,
- CX_PRI,
- NUMARGS
- };
-
- #ifndef BARDETAILPEN
- #define BARDETAILPEN (0x0009)
- #define BARBLOCKPEN (0x000A)
- #endif
-
- #define min(a,b) ((a)>(b)?(b):(a))
- #define max(a,b) ((a)<(b)?(b):(a))
- #define tolower(a) ((a)|0x20) /* Quick-and-dirty */
- #define isnum(a) (((a)>0x2F)&&((a)<0x3A))
-
- /* From sysiclass docs */
- #define LOWDEPTHWIDTH 17
- #define HIDEPTHWIDTH 23
-
- /* More stuff */
- static struct RastPort *MyRPort=NULL;
- static struct BitMap *MyBitMap=NULL;
-
- struct ExecBase *SysBase;
- struct DosLibrary *DOSBase;
- struct GfxBase *GfxBase;
- struct IntuitionBase *IntuitionBase;
- struct Library *UtilityBase;
- struct Library *CxBase;
- struct Library *IconBase;
- struct Library *TimerBase;
- struct LocaleBase *LocaleBase;
-
- struct Locale *Locale;
-
- static const char *Ver="$VER: TitleClock 3.3 (12.2.94)";
-
- static struct NewBroker newbrok =
- {
- NB_VERSION,
- "TitleClock",
- "TitleClock",
- "Displays clock in screen titlebar",
- NBU_UNIQUE|NBU_NOTIFY,
- 0,
- 0,
- 0,
- 0
- };
-
- static LONG Update=1;
- static LONG Fmt=FORMAT_DOS;
- static LONG Args[NUMARGS] = { (LONG)&Update, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (LONG)&(newbrok.nb_Pri)};
- static int LeftEdge;
-
- static char *PubPat=NULL, *ScrPat=NULL;
-
- static struct timerequest *TimerIO=NULL;
-
- static BOOL TimerPending=0, WildPub;
-
- /* Da main routine */
- int __saveds TitleClock(void)
- {
- struct Process *MyProc;
- struct WBStartup *WBs=NULL;
- struct DiskObject *Do=NULL;
- struct MsgPort *CXPort=NULL, *TimerPort=NULL;
- struct RDArgs *rdargs=NULL;
- CxObj *Broker=NULL;
- BOOL TimerFail=TRUE;
- int CXSig, TimerSig;
- long sig;
- CxMsg *CXMsg;
-
- /* set up ExecBase */
- SysBase = *((struct ExecBase **)(4L));
-
- if(!((MyProc=(struct Process *)FindTask(NULL))->pr_CLI))
- {
- /* Started from WB */
-
- /* Get Message */
- WaitPort(&(MyProc->pr_MsgPort));
- WBs=(struct WBStartup *)GetMsg(&(MyProc->pr_MsgPort));
- }
-
- /* Check version */
- if(SysBase->LibNode.lib_Version<37) /* Too Old */
- goto exit;
-
- /* Open needed libraries */
- DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37);
- GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37);
- IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37);
- UtilityBase=OpenLibrary("utility.library",37);
- CxBase=OpenLibrary("commodities.library",37);
- IconBase=OpenLibrary("icon.library",37);
- LocaleBase=(struct LocaleBase *)OpenLibrary("locale.library",38);
-
- if(!(DOSBase&&GfxBase&&IntuitionBase&&UtilityBase&&CxBase&&IconBase))
- /* didn't open */
- goto cleanup;
-
- if(LocaleBase)
- Locale=OpenLocale(NULL);
-
- if(WBs)
- {
- BPTR oldLock;
-
- oldLock=CurrentDir(WBs->sm_ArgList[0].wa_Lock);
-
- if(Do=GetDiskObject(WBs->sm_ArgList[0].wa_Name))
- {
- char *ToolValue;
-
- /* Update */
- if(ToolValue=FindToolType(Do->do_ToolTypes,"UPDATE"))
- StrToLong(ToolValue,&Update);
-
- /* Showdate */
- Args[SHOWDATE]=(long)FindToolType(Do->do_ToolTypes,"SHOWDATE");
-
- /* Showday */
- Args[SHOWDAY]=(long)FindToolType(Do->do_ToolTypes,"SHOWDAY");
-
- /* Shortday */
- Args[SHORTDAY]=(long)FindToolType(Do->do_ToolTypes,"SHORTDAY");
-
- /* Showsecs */
- Args[SHOWSECS]=(long)FindToolType(Do->do_ToolTypes,"SHOWSECS");
-
- /* Format */
- Args[FORMAT]=(long)FindToolType(Do->do_ToolTypes,"FORMAT");
-
- /* DateFormat */
- Args[DATEFORMAT]=(long)FindToolType(Do->do_ToolTypes,"DATEFORMAT");
-
- /* PubScreen */
- Args[PUBSCREEN]=(long)FindToolType(Do->do_ToolTypes,"PUBSCREEN");
-
- /* NonPubScreen */
- Args[SCREENPAT]=(long)FindToolType(Do->do_ToolTypes,"SCREENPAT");
-
- /* FrontScreen */
- Args[FRONTSCREEN]=(long)FindToolType(Do->do_ToolTypes,"FRONTSCREEN");
-
- /* DefScreen */
- Args[DEFSCREEN]=(long)FindToolType(Do->do_ToolTypes,"DEFSCREEN");
-
- /* CX_Priority */
- if(ToolValue=FindToolType(Do->do_ToolTypes,"CX_PRIORITY"))
- StrToLong(ToolValue,&Args[CX_PRI]);
- }
-
- CurrentDir(oldLock);
- }
- else
- if(!(rdargs=ReadArgs(TEMPLATE,Args,NULL)))
- {
- PrintFault(IoErr(),"TitleClock");
- goto cleanup;
- }
-
- newbrok.nb_Pri=*(int *)Args[CX_PRI];
-
- if(Args[FORMAT])
- {
- switch(tolower(((char *)Args[FORMAT])[1]))
- {
- case 'o': /* DOS */
- Fmt=FORMAT_DOS;
- break;
-
- case 'n': /* International */
- Fmt=FORMAT_INT;
- break;
-
- case 'm': /* American */
- Fmt=FORMAT_USA;
- break;
-
- case 'a': /* Canadian */
- Fmt=FORMAT_CDN;
- break;
- }
- }
-
- if(Args[PUBSCREEN])
- {
- int len;
-
- if(PubPat=AllocVec(len=StrLen((char *)Args[PUBSCREEN])*2+2,MEMF_ANY))
- {
- if((WildPub=ParsePattern((char *)Args[PUBSCREEN],PubPat,len))==-1)
- {
- FreeVec(PubPat);
- PubPat=NULL;
- }
- }
-
- }
-
- if(Args[SCREENPAT])
- {
- int len;
-
- if(ScrPat=AllocVec(len=StrLen((char *)Args[SCREENPAT])*2+2,MEMF_ANY))
- {
- if(ParsePattern((char *)Args[SCREENPAT],ScrPat,len)==-1)
- {
- FreeVec(ScrPat);
- ScrPat=NULL;
- }
- }
-
- }
-
- /* Args read */
-
- /* Allocate BitMap and RastPort */
- if(!(MyBitMap=AllocVec(sizeof(struct BitMap),MEMF_CLEAR|MEMF_PUBLIC)))
- goto cleanup;
-
- if(!(MyRPort=AllocVec(sizeof(struct RastPort),MEMF_CLEAR|MEMF_PUBLIC)))
- goto cleanup;
-
- InitRastPort(MyRPort);
- MyRPort->BitMap=MyBitMap;
-
- /* Set up timer.device */
- if(!(TimerPort=CreateMsgPort()))
- goto cleanup;
-
- TimerSig= 1L << TimerPort->mp_SigBit;
-
- if(!(TimerIO=(struct timerequest *)
- CreateIORequest(TimerPort,sizeof(struct timerequest))))
- goto cleanup;
-
- if(TimerFail=OpenDevice("timer.device",UNIT_WAITUNTIL,TimerIO,0))
- goto cleanup;
-
- /* Library pointer */
- TimerBase=TimerIO->tr_node.io_Device;
-
- /* Init timerequest */
- TimerIO->tr_node.io_Command=TR_ADDREQUEST;
- TimerIO->tr_time.tv_micro=0;
-
- if(!(CXPort=CreateMsgPort()))
- goto cleanup;
-
- CXSig = 1L << CXPort->mp_SigBit;
-
- newbrok.nb_Port=CXPort;
-
- if(!(Broker=CxBroker(&newbrok,NULL)))
- goto cleanup;
-
- ActivateCxObj(Broker,1L);
-
- /* Setup done */
-
- {
- int Abort=0, Enabled=1;
-
- UpdateClk();
-
- while(!Abort)
- {
- sig=Wait(CXSig|TimerSig|SIGBREAKF_CTRL_C);
-
- if(sig&TimerSig)
- {
- if(GetMsg(TimerPort))
- {
- TimerPending--;
- if(Enabled) UpdateClk();
- }
- }
-
- while(CXMsg=(CxMsg *)GetMsg(CXPort))
- {
- const int msgid=CxMsgID(CXMsg);
- const int msgtype=CxMsgType(CXMsg);
-
- ReplyMsg((struct Message *)CXMsg);
-
- if(msgtype==CXM_COMMAND)
- switch(msgid)
- {
- case CXCMD_DISABLE:
- Enabled=0;
- ActivateCxObj(Broker,0);
- break;
-
- case CXCMD_ENABLE:
- Enabled=1;
- if(!TimerPending) UpdateClk();
- ActivateCxObj(Broker,1);
- break;
-
- case CXCMD_KILL:
- case CXCMD_UNIQUE:
- Abort=1;
- }
- }
-
- if(sig&SIGBREAKF_CTRL_C) Abort=1;
- }
- if(TimerPending)
- {
- if(!CheckIO(TimerIO)) AbortIO(TimerIO);
- WaitIO(TimerIO);
- }
- }
-
- cleanup:
- CleanUp();
-
- /* Commodity stuff */
- if(Broker)
- {
- DeleteCxObj(Broker);
- while(CXMsg=(CxMsg *)GetMsg(CXPort))
- ReplyMsg((struct Message *)CXMsg);
- }
- if(CXPort) DeleteMsgPort(CXPort);
-
- /* Timer stuff */
- if(!TimerFail)
- CloseDevice(TimerIO);
- if(TimerIO) DeleteIORequest(TimerIO);
- if(TimerPort) DeleteMsgPort(TimerPort);
-
- FreeVec(PubPat);
- FreeVec(ScrPat);
-
- if(rdargs) FreeArgs(rdargs);
- if(Do) FreeDiskObject(Do);
-
- CloseLocale(Locale);
- CloseLibrary(LocaleBase);
- CloseLibrary(IconBase);
- CloseLibrary(UtilityBase);
- CloseLibrary(CxBase);
- CloseLibrary((struct Library *)IntuitionBase);
- CloseLibrary((struct Library *)GfxBase);
- CloseLibrary((struct Library *)DOSBase);
-
- exit:
- if(WBs)
- {
- /* Reply WBStartup */
- Forbid();
- ReplyMsg(WBs);
- }
-
- MyProc->pr_Result2=0;
- return 0;
- }
-
- void __asm SPFunc(register __a0 struct Hook *pHook, register __a1 char pChar)
- {
- if ((pChar&0x60) && ((int)pHook->h_Data - (int)pHook->h_SubEntry <
- MAXCLOCKLEN)) /* Quick-and-dirty isprint() + */
- /* make sure that we're not */
- /* printing too many chars. */
- *((*(char **)&(pHook->h_Data))++)=pChar;
- }
-
- /* Print hook */
- struct Hook PrintHook =
- {
- NULL, NULL, /* MinNode */
- (ULONG (* )())SPFunc, /* h_Entry, PrintFunc */
- NULL, /* h_SubEntry. Dirtily used as pointer for */
- /* where the string began. */
- NULL /* h_Data, where to put char */
- };
-
- /* print date */
- int SPrintD(char *Dest, char *Fmt, struct DateStamp *Date)
- {
- PrintHook.h_SubEntry=(ULONG (* )())(PrintHook.h_Data=Dest);
- FormatDate(Locale,Fmt,Date,&PrintHook);
- *((char *)PrintHook.h_Data)='\0';
-
- return ((int)((char *)PrintHook.h_Data-Dest)); /* return length of string */
- }
-
- /* Display clocks on appropriate screens */
- static void DisplayClk(char *clkstr, int clklen, struct Screen *cs)
- {
- if(AttemptLockLayerRom(cs->BarLayer))
- {
- struct DrawInfo *dri;
- struct TextFont *MyFont;
- int i, BltLen;
- UWORD FrontPen, BackPen;
- WORD dSize;
-
- MyFont=cs->BarLayer->rp->Font; /* No need to 'open' it */
-
- if(MyBitMap->Depth<min(cs->RastPort.BitMap->Depth,8)||MyBitMap->Rows<MyFont->tf_YSize||MyBitMap->BytesPerRow<cs->RastPort.BitMap->BytesPerRow)
- {
- /* Need 'better' rastport */
-
- FreeVec(MyBitMap->Planes[0]);
- InitBitMap(MyBitMap,max(MyBitMap->Depth,min(cs->RastPort.BitMap->Depth,8)),cs->Width,max(MyBitMap->Rows,MyFont->tf_YSize));
-
- if(!(MyBitMap->Planes[0]=AllocVec(MyBitMap->BytesPerRow*MyBitMap->Rows*MyBitMap->Depth,MEMF_CHIP)))
- {
- MyBitMap->Depth=0;
- goto next;
- }
-
- for(i=1;i<min(MyBitMap->Depth,8);i++)
- MyBitMap->Planes[i]=((UBYTE *)MyBitMap->Planes[i-1])+MyBitMap->BytesPerRow*MyBitMap->Rows;
- }
-
- if(dri=GetScreenDrawInfo(cs))
- {
- if(dri->dri_NumPens>=0x000A)
- {
- FrontPen=dri->dri_Pens[BARDETAILPEN];
- BackPen=dri->dri_Pens[BARBLOCKPEN];
- }
- else
- {
- FrontPen=dri->dri_Pens[DETAILPEN];
- BackPen=dri->dri_Pens[BLOCKPEN];
- }
- FreeScreenDrawInfo(cs,dri);
- }
- /* If we don't get DrawInfo, the pens will be somewhat random */
-
- SetFont(MyRPort,MyFont);
- SetDrMd(MyRPort,JAM2);
- SetAPen(MyRPort,FrontPen);
- SetBPen(MyRPort,BackPen);
- SetRast(MyRPort,BackPen);
-
- Move(MyRPort, MyFont->tf_XSize, MyFont->tf_Baseline);
-
- Text(MyRPort, clkstr, clklen);
-
- dSize = (cs->Flags&SCREENHIRES?HIDEPTHWIDTH:LOWDEPTHWIDTH);
-
- LeftEdge = cs->Width - (BltLen=MyRPort->cp_x+CLOCKOFFSET) - dSize;
-
- if(BltLen+dSize>cs->Width)
- BltLen=cs->Width-dSize;
-
- ClipBlit(MyRPort,0,0,cs->BarLayer->rp,LeftEdge,1,BltLen,MyFont->tf_YSize,0x0C0);
- next:
- UnlockLayerRom(cs->BarLayer);
- }
- }
-
- struct PSList
- {
- struct PSList *psl_Next;
- struct Screen *psl_Screen;
- };
-
- static struct PSList *LockPubScreens(UBYTE *Pattern)
- {
- struct PubScreenNode *psnode;
- struct PSList *mylist=NULL, *tmp, *last;
-
- if(psnode=(struct PubScreenNode *)LockPubScreenList())
- {
- while((psnode=(struct PubScreenNode *)psnode->ln_Succ)->ln_Succ)
- {
- if(!(psnode->psn_Flags&PSNF_PRIVATE)&&MatchPattern(Pattern,psnode->ln_Name))
- {
- if(tmp=AllocVec(sizeof(struct PSList),0L))
- {
- psnode->psn_VisitorCount++;
- tmp->psl_Screen=psnode->psn_Screen;
- #pragma msg 94 ignore push
- if(mylist) last->psl_Next=tmp;
- #pragma msg 94 pop
- else mylist=tmp;
- last=tmp;
- }
- }
- }
- tmp->psl_Next=NULL;
- UnlockPubScreenList();
- }
-
- return mylist;
- }
-
- static void UnlockPubScreens(struct PSList *list)
- {
- struct PSList *tmp;
-
- do {
- tmp=list->psl_Next;
- UnlockPubScreen(NULL,list->psl_Screen);
- FreeVec(list);
- }
- while(list=tmp);
- }
-
- /* Update clock */
- static void UpdateClk(void)
- {
- struct DateTime dt;
- static char DispStr[MAXCLOCKLEN];
- int StringLen=0;
-
- DateStamp(&dt);
-
- if(!Args[DATEFORMAT] || !LocaleBase)
- {
- dt.dat_Format = Fmt;
- dt.dat_Flags = 0;
- dt.dat_StrDay = NULL;
- dt.dat_StrDate= NULL;
- dt.dat_StrTime= NULL;
-
- DispStr[0]='\0';
-
- if(Args[SHOWDAY])
- {
- dt.dat_StrDay = DispStr;
-
- DateToStr(&dt);
- if(Args[SHORTDAY]) DispStr[3] = '\0';
-
- DispStr[StringLen=StrLen(DispStr)]=' ';
- StringLen++;
- }
-
- if(Args[SHOWDATE])
- {
- dt.dat_StrDay = NULL;
- dt.dat_StrDate= &DispStr[StringLen];
-
- DateToStr(&dt);
-
- DispStr[StringLen=StrLen(DispStr)]=' ';
- StringLen++;
- }
-
- dt.dat_StrDate= NULL;
- dt.dat_StrTime= &DispStr[StringLen];
-
- DateToStr(&dt);
-
- StringLen=StrLen(DispStr);
-
- if(!Args[SHOWSECS]) StringLen -= 3;
- }
- else
- {
- /* Use FormatDate */
- StringLen=SPrintD(DispStr,(char *)Args[DATEFORMAT],&dt);
- }
-
- /* Now display the things on the right screens */
- {
- ULONG ILock;
- struct Screen *cs;
-
- ILock=LockIBase(0);
-
- /* This is part while the IntuitionBase lock is held not-quite */
- /* legal. The AutoDoc says not to call any intuition, */
- /* graphics, etc functions while holding the lock, but it */
- /* seems to work. My guess is that the warning in the AutoDoc */
- /* is to keep people from locking up the machine trying to */
- /* draw while someone has a layer locked. If this is the */
- /* reason, then the following should not cause any problems */
- /* what so ever, since I won't draw unless I get to lock the */
- /* layer. If there is some other obscure reason, then this may */
- /* cause problems on some systems. But so far I haven't seen */
- /* or heard of any problems with it, and it's really the only */
- /* way to do what we want to do. Also, we probably hold the */
- /* lock for way too long trying to draw the clock on all the */
- /* right screens :-) */
-
- cs=IntuitionBase->FirstScreen;
-
- if(cs&&Args[FRONTSCREEN]) /* First Screen */
- {
- DisplayClk(DispStr,StringLen,cs);
- cs=cs->NextScreen;
- }
-
- if(ScrPat&&cs) /* Match screen title */
- {
- do
- {
- if(cs->DefaultTitle&&MatchPattern(ScrPat,cs->DefaultTitle))
- DisplayClk(DispStr,StringLen,cs);
- }
- while(cs=cs->NextScreen);
- }
-
- UnlockIBase(ILock);
-
- /* Public screens */
- if(PubPat)
- {
- if(WildPub)
- {
- struct PSList *pslist, *psl;
-
- if(psl=pslist=LockPubScreens(PubPat)) {
- do {
- DisplayClk(DispStr,StringLen,pslist->psl_Screen);
- }
- while(pslist=pslist->psl_Next);
- }
-
- UnlockPubScreens(psl);
- }
- else
- {
- if(cs=LockPubScreen((char *)Args[PUBSCREEN]))
- {
- DisplayClk(DispStr,StringLen,cs);
- UnlockPubScreen(NULL,cs);
- }
- }
- }
-
- /* Default public screen */
- if(Args[DEFSCREEN]&&(cs=LockPubScreen(NULL)))
- {
- DisplayClk(DispStr,StringLen,cs);
- UnlockPubScreen(NULL,cs);
- }
- }
-
- /* Rescheduele timer */
- GetSysTime(&TimerIO->tr_time);
-
- TimerIO->tr_time.tv_secs+=*(int *)Args[UPDATE];
- TimerIO->tr_time.tv_micro=0;
- SendIO(TimerIO);
- TimerPending++;
- }
-
- static void CleanUp(void)
- {
- if(MyBitMap)
- {
- FreeVec(MyBitMap->Planes[0]);
- FreeVec(MyBitMap);
- }
- FreeVec(MyRPort);
- }
-
- static int StrLen(const char *str)
- {
- int i;
-
- for(i=0;str[i];i++);
-
- return (i);
- }
-