[comp.sys.atari.st] Hacking fonts and calling from_alert

minow@bolt.dec.com (12/29/86)

#if 0
A few weeks ago, I asked for help in changing the system font (that
is used by Bconout, for example).  Thanks to the people who responded.
After digging through the Abacus manuals -- especially the BIOS dump,
and a lot of painful experimenting (read "hacking"), I've come up
with the following routines.  NOTE: there is no guarantee that they
will work on future BIOS releases, and are quite likely to fail
under normal circumstances.  Expect to have to reboot your machine.

If you use this to change the font, not the following restrictions
(discovered painfully, one at a time):

 -- The font character width must be 8.
 -- The font must be monospaced.
 -- The first value in the font (low_ade) must be zero.
 -- I think you can omit "uninteresting" characters, setting
    their offset table entries to zero.  I haven't tried this.

The following is included:
 -- startup()		Called from main() when your program starts.
 -- shutdown()		Must be called to exit the application.
 -- switch_font()	Switch to a named font.
 -- demo()		Demo to show how to call text_form_alert()
 -- text_form_alert()	Call form_alert from non-application
 -- gem_start()		Start GEM from scratch
 -- gem_stop()		Tear down GEM after form_alert() call.
 -- dumpslap()		Dump "secret" linea values.

Questions:
 -- How can I tell if the mouse is on when my application starts?
 -- How can I tell if I'm running from the shell, or as a desktop
    application, or as a desk accessory?  Must I conditionally-
    compile this information in?
 -- Is there a "supported" way to tell if the cursor is on?

Note that this is extracted from a larger program, and is completely
untested (it hasn't even been compiled). Sorry about the length of this
posting.  Thanks again for all the help.

Martin Minow
minow%thundr.dec@decwrl.dec.com
decvax!minow
#endif

#include	<osbind.h>
#include	<aesbind.h>
#include	<gemdefs.h>
#include	<linea.h>

#define	CON	2			/* Console			*/
#define PUTCON(c)	Bconout(CON, ((int) c))
#define	CURSOR_OFF	(PUTCON(ESC), PUTCON('f'))
#define CURSOR_ON	(PUTCON(ESC), PUTCON('e'))

#define NULL		0
#define SYS_FONT	2	/* Font index of 8x16 sys. font		*/	

/*
 * Define offsets into the working variables.  These are negative
 * offsets from the base of the linea data array. They are given
 * as address offsets.  They were calculated by dumping memory.
 */

struct linea_stuff {
  short v_cursor_is_off;	/*    Non-zero if cursor disabled	*/
  short v_unknown[0x95];	/* .. Uninteresting for now		*/
  short	v_font_height;		/* 2E Cell height in scanlines		*/
  short	v_max_cursor_x;		/* 2C Maximum cursor column		*/
  short v_max_cursor_y;		/* 2A Maximum cursor line (row)		*/
  short	v_scan_wrap;		/* 28 Word wrap to next scanline	*/
  short v_background_color;	/* 26 Background color			*/
  short v_forground_color;	/* 24 Foreground color			*/
  char	*v_cursor_screen_addr;	/* 22 Screen address of the cursor	*/
  short	v_who_knows;	/* ? */	/* 1E Value set by VDI ESC 101		*/
  short v_cursor_column;	/* 1C Current cursor column		*/
  short	v_cursor_row;		/* 1A Current cursor row		*/
  short	v_cursor_flash;		/* 18 Low byte has rate, high has count	*/
  char	*v_font_data;		/* 16 -> font data			*/
  short	v_hi_ade;		/* 12 Largest ascii code in font	*/
  short	v_low_ade;		/* 10 Smallest ascii code in font	*/
  short	v_font_width;		/* 0E Width of the font			*/
  short	v_has_screen_width;	/* 0C Has screen width in pixels	*/
  char	*v_font_char_off;	/* 0A -> font character offset table	*/
  short	v_cursor_flash_flags;	/* 06 Cursor blink controller		*/
  short	v_has_raster_lines;	/* 04 Has raster lines on screen	*/
  short	v_i_dont_know;		/* 02 Doesn't seem to be referenced	*/
};

typedef	struct	{			/* This turned out to be the	*/
	int	x;			/* same as a GRECT.		*/
	int	y;
	int	w;
	int	h;
}	BOX;

int		contrl[12];
int		intin[128];
int		ptsin[128];
int		intout[128];
int		ptsout[128];

int		gem_handle;
int		vdi_handle;
int		wi_handle;
struct linea_stuff	*slap;		/* Points to secret linea stuff	*/
struct la_font		*sys_font;	/* The 8x16 default font	*/
struct la_font		*curr_font;	/* The currently-displayed font	*/
int			cursor_was_off;	/* Set at startup, used at exit	*/

BOX			desk;
long			dummy;

int			debug = 0;

/*
 * Note: this main program is completely untested.
 */
main()
{
	startup();
	for (;;) {
	    demo();
	}
	shutdown();
}

/*
 * startup():
 *
 * Initialize desktop -- called when the program starts to do all
 * of the secret Gem-ish things.  This routine determines whether
 * the program was run from the Mark Williams shell, from the
 * desktop, or as a desk accessory (how? -- this may have to be
 * a compile-time parameter).
 */

startup()
{
	linea0();
	sys_font = la_init.li_a1[SYS_FONT];
	curr_font = sys_font;
	slap = ((struct linea_stuff *) la_init.li_a0) - 1;
	cursor_was_off = slap->v_cursor_is_off;
	if (cursor_was_off)		/* Assume called from desktop	*/
	    linea9();
#if 0
	dumpslap("Start");
	CURSOR_OFF;
	dumpslap("Cursor off");
	CURSOR_ON;
	dumpslap("Cursor on");
#endif
}

shutdown()
{
	if (curr_font != sys_font) {
	    switch_font(sys_font);
	}
	if (cursor_was_off)		/* Give cursor its state	*/
	    CURSOR_OFF;			/* at the start of the program	*/
	else {
	    CURSOR_ON;
	}
#if 0
	PUTCON(ESC);			/* Move cursor to the bottom of	*/
	PUTCON('Y');			/* the screen.  (Looks better)	*/
	PUTCON(slap->v_max_cursor_y + 0x20);
	PUTCON(0 + 0x20);
#endif
	PUTCON('\r');
	PUTCON('\n');
	/*
	 * If we're running as an accessory, we should longjmp to
	 * the top to wait for the application to be reselected.
	 */
	Pterm0();			/* Exit application		*/
}

switch_font(fp)
register struct la_font		*fp;
/*
 * This code duplicates the VDI ESC 102 code (page 440 in the ST Internals
 * BIOS listing).  I dumped memory to find out how it works, and you should
 * expect to do the same when you get new ROMS.
 */
{
	register struct linea_stuff	*sp;	/* -> secret stuff	*/
	register struct la_data		*lp;	/* -> normal stuff	*/

	sp = slap;				/* In reg. for speed	*/
	lp = la_init.li_a0;			/* Norm linea stuff	*/
	sp->v_font_height	= fp->font_height;
	sp->v_scan_wrap		= lp->ld_vwrap * fp->font_height;
	/*
	 * These are 1 less than the number of columns (and rows)
	 */
	sp->v_max_cursor_y
			= (sp->v_has_raster_lines / fp->font_height) - 1;
	sp->v_max_cursor_x
			= (sp->v_has_screen_width / fp->font_fat_cell) - 1;
	sp->v_font_width	= fp->font_width;
	sp->v_low_ade		= fp->font_low_ade;
	sp->v_hi_ade		= fp->font_hi_ade;
	sp->v_font_char_off	= fp->font_char_off;
	sp->v_font_data		= fp->font_data;
	curr_font = fp;				/* Remember new font	*/
}

/*
 * This function uses form_alert to get a response from the user.
 */
demo()
{
	register int	response;

	response = text_form_alert(2,
	    "[2][   Form Alert Demo ][Exit|Continue]");
	if (response == 1)
	    shutdown();
}


/*
 * This routine lets you call form_alert() from a program running under the
 * Mark Williams Shell.  It starts a Gem "application", calls form_alert()
 * then tears down the application.  It might be better to call appl_init()
 * once at the start.  Your corrections are welcome.
 */

int
text_form_alert(def_response, text)
int		def_response;
char		*text;
{
	register int	response;

	gem_start();
	response = form_alert(def_response, text);
	gem_stop();
	return (response);
}

/*
 * Hack the mouse and text cursor, then start a gem application
 * with a full-screen window.  When we return, the following
 * globals are initialized:
 *	gem_handle	-> handle for the physical screen
 *	vdi_handle	-> handle for the virtual workstation
 *	wi_handle	-> handle for the window
 * Also, the text (blinking box) cursor is off and the mouse is on.
 */
gem_start()
{
	register int	i;
	register int	*ld_contrl;
	register int	*ld_intin;
	int		work_in[11], work_out[57];

	linea0();				/* Grab the linea junk	*/
	ld_contrl = la_init.li_a0->ld_contrl;	/* -> control junk	*/
	ld_intin  = la_init.li_a0->ld_intin;	/* -> intin junk	*/
	CURSOR_OFF;				/* Disable text cursor	*/
	ld_contrl[1] = 0;			/* Enable the mouse	*/
	ld_contrl[3] = 1;			/* No matter how much	*/
	ld_intin[0] = 0;			/* It was disabled.	*/
	linea9();				/* Enable the mouse	*/
	if (appl_init() == -1)			/* form_alert needs an	*/
	    Pterm0();				/* init'ed application	*/
	gem_handle = graf_handle(&dummy, &dummy, &dummy, &dummy);
	for (i = 0; i < 10; i++)
	    work_in[i] = 1;
	work_in[10] = 2;
	vdi_handle = gem_handle;
	v_opnvwk(work_in, &vdi_handle, work_out);
	if (vdi_handle == 0)
	    Pterm0();
	/*
	 * Create a window big as all outdoors.
	 */
	wind_get(0, WF_WORKXYWH, &desk.x, &desk.y, &desk.w, &desk.h);
	wi_handle = wind_create(0, desk.x, desk.y, desk.w, desk.h);
}

/*
 * Close down the workstation and go back to the normal cursor.
 */
gem_stop()
{
	wind_delete(wi_handle);		/* Delete the window		*/
	v_clsvwk(vdi_handle);		/* And the workstation		*/
	appl_exit();			/* And AES			*/
	lineaa();			/* Disable mouse cursor		*/
	CURSOR_ON;			/* Turn on the text cursor	*/
}

/*
 * This routine dumps the secret linea stuff.
 */
dumpslap(why)
char		*why;
{
	register short			*shortp, *endp;
	register struct linea_stuff	*sp;
	int				i;

	printf("%s: v_cursor_was_off @ %06lx, linea @ %06lx", why,
		&slap->v_cursor_is_off, la_init.li_a0);
	printf(" cursor is %s\n",
		(slap->v_cursor_is_off) ? "off" : "on");
	i = 0;
	for (shortp = slap, endp = la_init.li_a0; shortp < endp; i++) {
	    if ((i & 0x7) == 0)
		printf("\n%06lx:", shortp);
	    printf(" %04x", *shortp++);		/* Dump in hex, first	*/
	}
	printf("\n");
	sp = slap;				/* Speed up access	*/
	dumpshort(&sp->v_font_height,		"Cell height in scanlines");
	dumpshort(&sp->v_max_cursor_x,		"Max. cursor column");
	dumpshort(&sp->v_max_cursor_y,		"Max. cursor row");
	dumpshort(&sp->v_scan_wrap,		"Word wrap to next scanline");
	dumpshort(&sp->v_who_knows,		"Set by VDI ESC 101");
	dumplong(&sp->v_font_data,		"-> font data");
	dumpshort(&sp->v_hi_ade,		"High character value");
	dumpshort(&sp->v_low_ade,		"Low character value");
	dumpshort(&sp->v_font_width,		"Font width");
	dumpshort(&sp->v_has_screen_width,	"Has screen width in pixels");
	dumplong(&sp->v_font_char_off,		"-> character offset table");
	dumpshort(&sp->v_has_raster_lines,	"Number of raster lines");
	dumpshort(&sp->v_i_dont_know,		"Unreferenced?");
}

dumpshort(ip,	what)
short		*ip;
char		*what;
{
	register int	offset;

	offset = ((char *) la_init.li_a0) - ((char *) ip);
	printf("%04x %5d @ %06lx [%02x]: %s\n",
		*ip, *ip, ip, offset, what);
}

dumplong(ip, what)
long		*ip;
char		*what;
{
	register int	offset;

	offset = ((char *) la_init.li_a0) - ((char *) ip);
	printf("    %06lx @ %06lx [%02x]: %s\n",
		*ip, ip, offset, what);
}