home *** CD-ROM | disk | FTP | other *** search
- // =======================================================================
-
- /* SetFont 2.7 - by Dave Haynie
-
- BIX: hazy
- Usenet: {uunet|rutgers}!cbmvax!daveh
- PLINK: D-Dave H
- Drink: Guinness
-
- BUSINESS:
-
- This program is complete, real, and true public domain software.
- Do with it what you will as long as you don't remove my name from it.
- Feel free to enhance this as you see fit. I may eventually make one
- that's better....
-
- ABOUT IT:
-
- SetFont V2.7 cleans up all known bugs in previous SetFont versions.
- The code is GREATLY cleaned up and simplified from SetFont V2.0. I no
- longer free any fonts that were previously set. V2.0 did too much
- freeing, but even with that, it is possible that another program could get
- a pointer to the font or font descriptor in a window or screen and choke
- if that's freed. That may not be good behavior, but this way's safer. A
- future version will probably track fonts opened and closed by SetFont
- itsself so that it can reclaim some of it's resources and still be
- reasonably safe. Right now I have no way of knowing if the font or
- descriptor I see is even really owned by SetFont. SetFont 2.7 also cleans
- up the font open ordering, once and for all. Apparently, the font system
- is broken or confused. In SetFont 2.5, I opened a disk font first, and
- ended up with multiple copies of a single font in RAM. In SetFont 2.6,
- I reversed the order and ended up missing disk fonts, as the software
- took the closest front to what I wanted from RAM. Now I open both damn
- fonts, take the closest to what I'm looking for from the two, and close
- the other. Ties go to the RAM font.
-
-
- CONFLICTS:
-
- There are a few potential problems the general notion of SetFont in
- the Amiga system. First of all, many programs are written to support only
- the topaz 8 (80 column) font (sloppy, I know, but that's life). If you're
- a 60 column user, you've probably experienced this before. It's not a
- problem with the Amiga as a whole, since most of the system will adjust
- itself. But it may be a problem with programs that have a fixed idea of
- what a font should look like. Most 80 column fonts work with most
- applications, and an 80 column 8x8 font will work just about everywhere.
- Some programs, like CLI for instance, have trouble with proportionally-
- spaced fonts. The best thing to do is try out the font you like. One
- final problem is that some applications ask the WorkBench screen to close
- when they start up. It'll close if there's nothing else open on it, but
- when it re-opens, it'll restart with the Preferences-selected font, not
- the SetFont selected font. Of course, preferences doesn't support
- arbitrary fonts (which is why this program is even necessary). Oh well,
- maybe day.
- */
-
- #include <exec/types.h>
- #include <exec/io.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <graphics/gfxbase.h>
- #include <graphics/text.h>
- #include <graphics/rastport.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <intuition/intuition.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- // =========================================================================
-
- // Miscellaneous stuff.
-
- extern TextFont *OpenDiskFont(const TextAttr *);
-
- inline BPTR CADDR(APTR cptr) { return BPTR(ULONG(cptr) >> 2); }
-
- inline void fail(char *a, char *b = NULL) { printf(a,b); exit(10); }
-
- inline UWORD abs(UWORD x) { return (x > 0)?x:(-x); }
-
- inline MsgPort *contask(MsgPort *port) {
- return (MsgPort *) ((port->mp_SigTask->ln_Type == NT_PROCESS)
- ? ((Process *)port->mp_SigTask)->pr_ConsoleTask
- : NULL);
- }
-
- // =========================================================================
-
- // This is the "smart" font class. SmartFont items stay around after the
- // program exits if they appear to have been used. As it turns out, the
- // Amiga font system looks somewhat broken. If I OpenDiskFont(), I load
- // the font, even if it's in memory. If I OpenFonr(), I get the closest
- // match to the font I want from the list of fonts in memory, not the
- // big picture. So SmartFont now gets a bit smarter, and knows how to
- // find the best match from both possible sources. The font opening order
- // is important, since if I fetch a disk font, I'm sure to find it in RAM
- // afterward.
-
- class SmartFont {
- private:
- static BOOL aok; // Font checks out
- TextAttr sfattr; // Font descriptor
-
- public:
- SmartFont(char *n, UWORD s);
-
- TextFont *font();
-
- TextAttr *attr() {
- TextAttr *a = (TextAttr *)AllocMem(sizeof(TextAttr),MEMF_PUBLIC|MEMF_CLEAR);
- a->ta_Name = (char *)AllocMem(strlen(sfattr.ta_Name)+1,MEMF_PUBLIC|MEMF_CLEAR);
- strcpy(a->ta_Name,sfattr.ta_Name);
- a->ta_YSize = sfattr.ta_YSize;
- return a;
- }
- char *name() { return sfattr.ta_Name; }
- UWORD size() { return sfattr.ta_YSize; }
- };
-
- SmartFont::SmartFont(char *n, UWORD s = 8) {
- strcat(strcpy(sfattr.ta_Name = new char[strlen(n)+6],n),".font");
- sfattr.ta_YSize = (s>2)?s:8;
- sfattr.ta_Style = sfattr.ta_Flags = 0;
-
- if (!aok) {
- TextFont *f = font();
- CloseFont(f);
- aok = TRUE;
- }
- }
-
- TextFont *SmartFont::font() {
- TextFont *memf, *dskf;
-
- if ((memf = OpenFont(&sfattr)) && sfattr.ta_YSize == memf->tf_YSize)
- return memf;
-
- dskf = OpenDiskFont(&sfattr);
-
- if (!memf && !dskf) fail("Font \"%s\" not found\n",sfattr.ta_Name);
- if (!memf && dskf)
- return dskf;
- else if (!dskf && memf)
- return memf;
- else if (abs(sfattr.ta_YSize - memf->tf_YSize) <=
- abs(sfattr.ta_YSize - dskf->tf_YSize)) {
- CloseFont(dskf);
- return memf;
- }
- CloseFont(memf);
- return dskf;
- }
-
- // =========================================================================
-
- // These classes manage the places that fonts are hidden.
-
- // This is the basic place node
-
- class PlaceNode : public Node {
- private:
- static Window *pwin;
- static Screen *pscr;
-
- public:
- PlaceNode();
- PlaceNode *next() { return (PlaceNode *)Node::next(); }
-
- void testwindow() { if (!pwin) fail("Window not found\n"); }
- void testscreen() { if (!pscr) fail("Screen not found\n"); }
-
- Window *window() { return pwin; }
- Screen *screen() { return pscr; }
-
- virtual void set(SmartFont *f) {
- testwindow();
- SetFont(window()->graphic(),f->font());
- printf("\033c"); // Re-init window's conunit
- (void)flushall();
- }
- };
-
- // Initialize the static stuff, once.
-
- PlaceNode::PlaceNode() {
- if (pwin) return;
-
- StandardPacket *packet = new StandardPacket;
- InfoData *info = new InfoData;
- MsgPort *port = new StdPort;
-
- // Find the window
- if (contask(port)) {
- packet->sendio(contask(port),port,ACTION_DISK_INFO,CADDR(info));
- (void)port->wait();
- pwin = (Window *)info->id_VolumeNode;
- } else
- pwin = NULL;
- delete port;
- delete info;
- delete packet;
-
- // Find the screen
- pscr = (pwin) ? pwin->screen() : NULL;
- }
-
- // These are the derived special nodes, one for each "place".
-
- #define WindowNode PlaceNode
-
- class ScreenNode : public PlaceNode {
- public:
- void set(SmartFont *f) {
- testscreen();
- if (strcmp(screen()->Font->ta_Name,f->name()) == 0)
- screen()->Font->ta_YSize = f->size();
- else
- screen()->Font = f->attr();
- }
- };
-
- class TitleNode : public PlaceNode {
- public:
- void set(SmartFont *f) {
- testscreen();
- SetFont(screen()->graphic(),f->font());
- }
- };
-
- class BarNode : public PlaceNode {
- public:
- void set(SmartFont *f) {
- testscreen();
- SetFont(screen()->BarLayer->rp,f->font());
- }
- };
-
- // This is the place list, which links a number of place nodes, and also
- // manages to go work like finding windows, etc.
-
- class PlaceList : public List {
- public:
- PlaceList(int argc, char **argv);
- PlaceNode *first() { return (PlaceNode *)List::first(); }
- };
-
- // The PlaceList constructor does a great deal of the work. It looks up
- // the window data, then parses the command line to build the place
- // list.
-
- PlaceList::PlaceList(int argc, char **argv) {
- // Parse our input arguments
- for (short i = 0; i < argc; ++i)
- switch (toupper(argv[i][0])) {
- case 'B': add(new BarNode); break;
- case 'S': add(new ScreenNode); break;
- case 'T': add(new TitleNode); break;
- case 'W': add(new WindowNode); break;
- default : break;
- }
- if (is_empty()) {
- add(new BarNode);
- add(new ScreenNode);
- add(new TitleNode);
- add(new WindowNode);
- }
- }
-
- // =========================================================================
-
- // Prints help notice
-
- void PrintNotice() {
- printf("SetFont V2.7 by Dave Haynie\n\n");
- printf("Usage: SetFont [fontname [point [place]]]\n");
- printf(" where:\n");
- printf(" \2331mfontname\2330m is the font's name (e.g. \"topaz\")\n");
- printf(" \2331mpoint\2330m is the point size (default is 8)\n");
- printf(" \2331mplace\2330m pick the place, one or more of:\n");
- printf(" \2331mBAR\2330m set the barlayer font only\n");
- printf(" \2331mSCREEN\2330m set the screen font only\n");
- printf(" \2331mTITLES\2330m set the screen titles only\n");
- printf(" \2331mWINDOW\2330m set the window's font only\n\n");
- printf("If no \2331mplace\2330m switch is given, everything is set.\n\n");
- exit(0);
- }
-
- // The main function
-
- void main(int argc, char *argv[]) {
- // Automatic help command
- if (argc < 2 || argv[1][0] == '?') PrintNotice();
-
- // Process the command-line arguments, AmigaDOS style.
- PlaceList *plist = new PlaceList(argc-2,&argv[3]);
-
- // Get the font if it's there.
- SmartFont *font = new SmartFont(argv[1],atoi(argv[2]));
-
- // Here we apply all the requested changes.
- for (PlaceNode *n = plist->first(); n->next(); n = n->next()) n->set(font);
-
- // And we're done!
- exit(0);
- }
-