[comp.sources.amiga] v02i102: setfont - set system font v2.5

page@swan.ulowell.edu (Bob Page) (12/29/88)

Submitted-by: kim@uts.amdahl.com (Kim E. DeVaughn)
Posting-number: Volume 2, Issue 102
Archive-name: fonts/setfont25.1

[executable in comp.binaries.amiga.  ..Bob]

#	This is a shell archi
ve.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	SetFont.cp
#	SetFont.doc
# This archive created: Wed Dec 28 13:19:28 1988
cat << \SHAR_EOF > SetFont.cp
// =======================================================================

/* SetFont 2.5 - 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.5 cleans up all known bugs in SetFont V2.0, and it's
   the first C++ version.  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.

   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 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.

class SmartFont {
   private:
      static BOOL aok;			// Font checks out	
      TextAttr	  sfattr;		// Font descriptor
      
   public:
      SmartFont(char *n, UWORD s);

      TextFont *font() {
         TextFont *f = OpenDiskFont(&sfattr);

         if (!f) f = OpenFont(&sfattr);
         if (!f) fail("Font \"%s\" not found\n",sfattr.ta_Name);
         return f;
      }
      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;
   }
}

// =========================================================================
 
// 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 2.5 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);
}
SHAR_EOF
cat << \SHAR_EOF > SetFont.doc


			SetFont V2.5 by Dave Haynie


	SetFont V2.5 is a public domain program designed to allow the system
font of the Amiga to be changed in various different ways.  The program is
called from a shell or startup-sequence script, and has the form:

	SetFont [fontname [point [places]]]

	where:

		fontname	Specifys the name of a standard Amiga 
				bitmapped font from the FONTS: directory.
				While any font can in theory be used, the
				system has trouble with very large ones,
				and some programs may have trouble with any
				font that's not 8x8.

		point		Specifys the height of the font, in pixels.
				If that actual size isn't found, the closest
				available is substituted.  The default for
				this is 8.

		places		There are several places the system keeps
				fonts.  When you change to a working font
				you may want that font everywhere in the
				system, in which case, no specifier is set.
				Otherwise, the following places are known
				by SetFont:

		    BAR		This is the "BarLayer" font for the WorkBench
				screen.  Among other things, the text in any
				string gadgets BEFORE you select them comes
				from this location.

		    SCREEN	This specified the default font for the 
				WorkBench screen.  All menus and newly built
				windows will inherit this font as their 
				default font.  Technically speaking, this is
				a font descriptor stored in the screen
				structure.

		    TITLES	This specifies the font that's mainly used
				for window title bars.  Technically speaking,
				this specifies the font of the screen's
				RastPort.

		    WINDOW	This specifies the font for the current window.
				It will case that window to be cleared.  The
				reason for this is that the window's font is
				not a default, but inherited from the screen
				and stored in the window's ConUnit.  That
				screen clear is the result of rebuilding the
				window's ConUnit to bring in the new font.

	And that's about it.  Please feel free to use this program and the
source code as you see fit.  If you find any bugs, please let me know about
them.

		-Dave Haynie

		PLINK  :	D-Dave H
		bix    :	hazy
		usenet :	{rutgers,uunet}!cbmvax!daveh
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS
 Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.