/*
 * Musmus.c
 *
 * Backbone for the musmus application.
 *  Musus Umbra, 1997
 */

static char 			*version = "1.24 (26 Oct 1998)";

#include "muscode.h"		/* some functions coded in assembler */
#include "chooseres.h"		/* high/low res sprite choosing fn   */
#include "query.h"			/* query/informational dbox handler  */
#include "tests.h"			/* startup tests for the !Boot/etc.  */
#include "iconnums.h"		/* the icon numbers in the templates */

#include "Desklib:Core.h"
#include "Desklib:Wimp.h"
#include "Desklib:Window.h"
#include "Desklib:Template.h"
#include "Desklib:Menu.h"
#include "Desklib:Icon.h"
#include "Desklib:Resource.h"
#include "Desklib:Msgs.h"
#include "Desklib:Error.h"
#include "Desklib:Event.h"
#include "Desklib:EventMsg.h"
#include "Desklib:Handler.h"
#include "Desklib:Screen.h"
#include "Desklib:WimpSWIs.h"
#include "Desklib:Font.h"
#include "Desklib:Coord.h"
#include "Desklib:GFX.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*--------------------------------------------------------------------------*/


#define BOOTPATH "<Boot$ToBeTasks>.!Musmus"
#define OLDBOOTPATH "<Boot$ToBeTasks>.Musmus"

/* define ROMFONTS to enable detection of ROM fonts rather than
   naively using Wimp$Font all the time.  For the sake of IconThang,
   this is undefined here :) */
#undef ROMFONTS

/* define CRUDESIZE to force font size to be modified in steps of
   0.25pt rather than 16ths */
#undef CRUDESIZE

/* Vertical offset in OS units to plot the fonts at in the preview window */
#define FONT_V_OFF 6

/*--------------------------------------------------------------------------*/


/* These are the options we control */

static char				font_name[60]  = "";	/* "" => system font */
static int				font_size      = 192;	/* 16ths */
static int				font_width     = 192;
static int				window2d       = 0;		/* 2d window tools? */
static int				textures       = 0;		/* use textures? */
static int				musmus_texture = 0;		/* musmus/RPC texture */
static int				desktop3d      = 0;		/* 3D desktop */
static int				dragasprite    = 0;		/* solid icon drags */
static int				solid          = 0;		/* ... (not) transparent */
static int				dither         = 0;		/* more dithering */
static int				toggle         = 0;		/* reverse toggle behavior */


/* These are Wimp related things */

static BOOL 			quit = FALSE;
static menu_ptr			main_menu = NULL;
static menu_ptr			font_menu = NULL;
static menu_ptr			size_menu = NULL;
static window_handle	info_box = 0;
static window_handle	auth_win = 0;
static window_handle	main_win = 0;

static int debug;


/*--------------------------------------------------------------------------*/

/* macros for the crude/fine font size selection */

#ifdef CRUDESIZE
#define FONT_SIZE_MASK (~3)
#define FONT_SIZE_STEP 4
#else
#define FONT_SIZE_MASK (~0)
#define FONT_SIZE_STEP 1
#endif

/*--------------------------------------------------------------------------*/




/*--------------------------------------------------------------------------*/

/* debug message code */

static void dbm( char *fmt, ... )
{
	va_list ap;
	static FILE *debf = NULL;

	if ( !debug ) { return; }

	va_start(ap,fmt);
	if ( !debf ) { debf=fopen("Musmus:DEBUGOUT","w"); }
	if ( !debf ) { return; }

	vfprintf(debf,fmt,ap);
	fprintf(debf,"\n");
	va_end(ap);
}





static void test_upgrade(void)
{
	if ( File_Type(OLDBOOTPATH) == 0x1000 )
		if ( rename(OLDBOOTPATH,BOOTPATH) )
			if ( query_box("bad.upd8") )
				exit(1);
}


static char *decode_font_name(char *name)
{
	static char buffer[64];
	char *d = buffer;
	if ( name[0]!='\\' ) { return name; }
	if ( name[1]=='F' )
	{
		name+=2;
		while ( *name != '\\' )
			if ( (*d++ = *name++) == 0 ) { break; }
		*d = 0;
		return buffer;
	}
	if ( name[1]=='f' )
	{
		name+=2;
		while ( *name++!=' ' )
			;
		while ( *name != '\\' )
			if ( (*d++ = *name++) == 0 ) { break; }
		*d = 0;
		return buffer;
	}
	return name;
}


/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/

static void read_config( void )
{
	/*char b[32];*/
	/*int cmos_font = (Read_CMOS(140) & (15<<1))>>1;*/
	textures = ((Read_CMOS(140) & 128) == 0);
	musmus_texture = (File_Type(BOOTPATH".Texture")==0xff9);
	solid = (File_Type(BOOTPATH".SolidDrags")==0xffb);
	desktop3d = (Read_CMOS(140) & 1);
	window2d = (ToolSprSize()<16*1024);		/* icky test, or what? */
	dragasprite = (Read_CMOS(28) & 2);
	dither = (Read_CMOS(28) & 8);
	toggle = (Read_CMOS(28) & 16);
	GetWimpFont(font_name,&font_width,&font_size);
}

#if 0
*	switch ( cmos_font )
*	{
*		case 1 :	/* System font */
*			*font_name = 0;
*			break;
*		case 0 :	/* Wimp$Font variables */
*			if ( !OSVar(font_name,60,"Wimp$Font") )
*			{
*				/* not defined, ergo use System Font */
*				*font_name = 0;
*			}
*			else
*			{
*				/* read the other vars */
*				font_size = OSVar(b,32,"Wimp$FontSize") ? atoi(b) : 192;
*				font_width = OSVar(b,32,"Wimp$FontWidth") ? atoi(b) : 192;
*			}
*			break;
*		default :
*			sprintf(b,"rfs.font%d",cmos_font);
*			if ( !Msgs_Lookup(b,font_name,60) )
*				*font_name = 0;
*			font_size = 192;
*			font_width = 192;
*			break;
*	}
*}
#endif



/*--------------------------------------------------------------------------*/

static BOOL cant_set(char *why)
{
	quit = query_box2("err.set",why);
	return FALSE;
}

static char *itoa(int i)
{
	static char buffer[32];
	sprintf(buffer,"%d",i);
	return buffer;
}


/*--------------------------------------------------------------------------*/


static BOOL write_config( void )
{
	char conf[1024];
	int  cmos = (Read_CMOS(140) & (3<<5));
	int  cmos2 = (Read_CMOS(28) & 229);
	os_error *e;

	dbm("Making directory '%s'",BOOTPATH);

	e = Make_Dir( BOOTPATH );
	if (e) { return cant_set(e->errmess); }

	*conf=0;					/* terminate the string... */

	dbm("Building font config");

	if ( !*font_name )			/* ie. the system font */
	{
		cmos |= (1<<1);
		strcat(conf,"|| System font is configured\n");
	}

#ifdef ROMFONTS
	else
	{
		dbm("Checking for ROM font");
		/* check to see if we can use a ROM font */
		if ( font_size==192 && font_width==192 )
		{
			int i;
			char *dn = decode_font_name( font_name );
			char buf1[32],buf2[60];
			for ( i=2; i<14 ; i++ )
			{
				sprintf(buf1,"rfs.font%d",i);
				if ( Msgs_Lookup(buf1,buf2,60) )
					if ( !strcmp(buf2,dn) )
						break;
			}
			if ( i<14 )
			{
				dbm("ROM font detected");
				cmos |= (i<<1);
				strcat(conf,"|| A ROM font is configured\n");
			}
		}
	}
#endif


	if ( !*conf )		/* ie. need to write font details */
	{
		dbm("Writing Wimp$Font* to buffer");
		sprintf(conf,	"|| Font configuration:\n"
						"Set Wimp$Font      \"%s\"\n"
						"Set Wimp$FontSize  \"%d\"\n"
						"Set Wimp$FontWidth \"%d\"\n",
						font_name, font_size, font_width );
		/* strcat(conf,"/BootResources:Configure.FontChange\n"); */
		dbm("Setting Wimp$Font*");
		SetVarVal("Wimp$Font",font_name);
		SetVarVal("Wimp$FontSize",itoa(font_size));
		SetVarVal("Wimp$FontWidth",itoa(font_width));
	}


	if ( desktop3d ) { cmos |= 1; }

	if ( !textures )
	{
		dbm("Removing 'texture'",BOOTPATH);
		cmos |= 128;
		remove(BOOTPATH".texture");
	}
	else
	{
		if ( musmus_texture )
		{
			dbm("Checking existence of Musmus texture");
			if ( File_Type(BOOTPATH".texture")!=0xff9 )
			{
				dbm("Not detected; copying 'Musmus:musmus' as 'texture'");
				e = Copy_File(BOOTPATH".texture","Musmus:musmus");
				if (e) { return cant_set(e->errmess); }
			}
			dbm("Writing iconsprites command to buffer");
			strcat(conf,"\n|| Mumsus Texture:\nIconSprites "
						"<obey$dir>.texture\n");
			dbm("Executing 'WimpKillSprite tile_1-*'");
			OSCLI("%WimpKillSprite tile_1-32");
			OSCLI("%WimpKillSprite tile_1-16");
			OSCLI("%WimpKillSprite tile_1-8");
			OSCLI("%WimpKillSprite tile_1-4");
			dbm("Executing 'iconsprites musmus:musmus'");
			OSCLI("iconsprites musmus:musmus");
		}
		else
		{
			dbm("Removing texture");
			remove(BOOTPATH".texture");
			dbm("Writing iconsprites command to buffer");
			if ( !tile_1_na )
			{
				strcat(conf,"\n|| RiscPC Texture:\nIconSprites "
							"BootResources:!Configure.tile_1\n");
			}
			else
			{
				dbm("Tile_1 is n/a, writing dummy line");
				strcat(conf,"\n|| RiscPC Texture n/a!\n\nIconSprites "
						"BootResources:!Configure.tile_1\n");
			}
			dbm("Executing 'WimpKillSprite tile_1-*'");
			/* was: Wimp_StartTask("WimpKillSprite tile_1-8"); */
			OSCLI("%WimpKillSprite tile_1-32");
			OSCLI("%WimpKillSprite tile_1-16");
			OSCLI("%WimpKillSprite tile_1-8");
			OSCLI("%WimpKillSprite tile_1-4");
			dbm("Executing 'iconsprites tile_1'");
			OSCLI("%iconsprites BootResources:!Configure.tile_1");
		}
	}

	if ( solid )
	{
		int os;
		dbm("Removing transdrags");
		remove(BOOTPATH".transdrags");
		dbm("Copying soliddrags");
		Copy_File(BOOTPATH".SolidDrags","Musmus:SolidDrags");
		dbm("Writing soliddrags call to buffer");
		strcat(conf,"\n|| Solid icon drags\n"
					"wimpslot -min 32K -max 32K\n"
					"/<obey$dir>.SolidDrags\n");
		dbm("Setting Wimpslot");
		os = NextSlot(32<<10);
		dbm("Running SolidDrags");
		Wimp_StartTask("Run Musmus:SolidDrags");
		dbm("Restoring Wimpslot");
		NextSlot(os);
	}
	else
	{
		int os;
		dbm("Removing soliddrags");
		remove(BOOTPATH".soliddrags");
		dbm("Copying TransDrags");
		Copy_File(BOOTPATH".TransDrags","Musmus:TransDrags");
		dbm("Writing transdrags call to buffer");
		strcat(conf,"\n|| 'Normal' transparent icon drags\n"
					"wimpslot -min 32K -max 32K\n"
					"/<obey$dir>.TransDrags\n");
		dbm("Setting Wimpslot");
		os = NextSlot(32<<10);
		dbm("Running TransDrags");
		Wimp_StartTask("Run Musmus:TransDrags");
		dbm("Restoring Wimpslot");
		NextSlot(os);
	}

	if ( window2d )
	{
		dbm("Writing 2D window tools call to buffer");
		strcat(conf,"\n|| 2D window tools:\nToolSprites "
					"BootResources:Configure.2DTools\n");
		dbm("Checking toolsprite size");
		if ( ToolSprSize()>16*1024 )
		{
			dbm("Executing ToolSprites 2DTools");
			Wimp_StartTask("Toolsprites BootResources:Configure.2DTools");
		}
	}
	else
	{
		dbm("Checking toolsprite size");
		if ( ToolSprSize()<16*1024 )
		{
			dbm("Executing ToolSprites Windowmanager:Tools");
			Wimp_StartTask("Toolsprites WindowManager:Tools");
		}
	}

	dbm("Copying Redraw");
	Copy_File(BOOTPATH".Redraw","Musmus:Redraw");
	dbm("Writing Redraw call to buffer");
	strcat(conf,"\n|| Force a screen redraw\nDo Filer_Run <obey$dir>.Redraw\n");

	dbm("Writing buffer to !Boot");
	e = Save_Typed(BOOTPATH".!Run",0xfeb,conf,strlen(conf)-1);
	if (e) { return cant_set(e->errmess); }

	if ( dragasprite ) { cmos2 |= 2; }
	if ( dither ) { cmos2 |= 8; }
	if ( toggle ) { cmos2 |= 16; }

	dbm("Writing CMOS values");
	if ( Write_CMOS(140,cmos)<0 ) { return query_box("err.cwrite"); }
	if ( Write_CMOS(28,cmos2)<0 ) { return query_box("err.cwrite"); }

	dbm("All done!");
	return TRUE;
}


/*--------------------------------------------------------------------------*/

/* Preview window code (1.21) */

static font_handle preview_font = -1;
static window_handle preview_window = 0;


static BOOL Hnd_CloseP( event_pollblock *b, void *ref )
{
	if ( preview_window )
		Window_Delete(preview_window);
	preview_window = 0;
	if ( preview_font != -1 )
		Font_LoseFont(preview_font);
	preview_font = -1;

	return TRUE;
}


static void font_changed( BOOL redraw )
{
	os_error *e;
	window_info wi;

	if ( preview_font != -1 )
		Font_LoseFont(preview_font);
	preview_font = -1;

	/* Close the preview window (if open) if system font is selected */
	if ( !*font_name )
		Hnd_CloseP(0,0);

	/* no point in going any further if the window isn't open :) */
	if ( !preview_window ) { return; }

	if ( *font_name )
	{
		e = Font_FindFont( &preview_font, font_name,
												font_width, font_size, 0,0 );
		if (e) { Msgs_ReportFatal(e->errnum,"err.fontf",e->errmess); }
	}

	if ( !redraw ) { return; }

	e = Window_GetInfo3(preview_window,&wi);
	if (e) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }

	/* copy the workarea into the screenrect */
	wi.block.screenrect = wi.block.workarearect;
	/* Do the redraw */
	e = Wimp_ForceRedraw((window_redrawblock*)&wi);
}



static BOOL Hnd_RedrawP( event_pollblock *b, void *ref )
{
	BOOL more;
	os_error *e;
	window_redrawblock rb;
	wimp_point p;
	char text1[256];
	char text2[256];
	int l1,l2;

	Msgs_Lookup("test.text1",text1,255);
	Msgs_Lookup("test.text2",text2,255);

	/* Widths of the strings in OS units */
	l1 = 16*strlen(text1);
	l2 = 16*strlen(text2);


	rb.window = preview_window;
	e = Wimp_RedrawWindow( &rb, &more );
	if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
	if ( !more ) { return TRUE; }

	/* if the font handle isn't set up, do it now */
	if ( preview_font == -1 ) { font_changed( FALSE ); }

	while ( more )
	{

		Wimp_SetColour(0);
		GFX_Move( rb.rect.min.x, rb.rect.min.y );
		GFX_Draw( rb.rect.min.x, rb.rect.max.y-2 );
		GFX_Draw( rb.rect.max.x, rb.rect.max.y-2 );
		GFX_Move( rb.rect.min.x+2, rb.rect.min.y );
		GFX_Draw( rb.rect.min.x+2, rb.rect.max.y-4 );
		GFX_Draw( rb.rect.max.x, rb.rect.max.y-4 );
		Wimp_SetColour(4);
		GFX_Move( rb.rect.min.x+2, rb.rect.min.y );
		GFX_Draw( rb.rect.max.x-2, rb.rect.min.y );
		GFX_Draw( rb.rect.max.x-2, rb.rect.max.y-2 );
		GFX_Move( rb.rect.min.x+4, rb.rect.min.y+2 );
		GFX_Draw( rb.rect.max.x-4, rb.rect.min.y+2 );
		GFX_Draw( rb.rect.max.x-4, rb.rect.max.y-4 );

		/* Display the system font lines of text */
		p.x = 16; p.y = -16;
		Coord_PointToScreen( &p, (convert_block*)(&(rb.rect)) );
		Wimp_SetColour(7);
		GFX_Move( p.x, p.y );
		printf(text1);
		GFX_Move( p.x, p.y-96 );
		printf(text2);

		/* Now plot margins */
		Wimp_SetColour(11);				/* red */

		/* left side margins */
		GFX_Move(p.x-2,p.y+2);
		GFX_Draw(p.x-2,p.y-66);
		GFX_Move(p.x-2,p.y-96);
		GFX_Draw(p.x-2,p.y-162);
		/* right side margin, text 1 */
		GFX_Move(p.x+l1+2,p.y+2);
		GFX_Draw(p.x+l1+2,p.y-66);
		/* right side margin, text 2 */
		GFX_Move(p.x+l2+2,p.y-96);
		GFX_Draw(p.x+l2+2,p.y-162);
		/* bottom margin text 1 */
		GFX_Move(p.x-2,p.y-66);
		GFX_Draw(p.x+l1+2,p.y-66);
		/* bottom margin text 2 */
		GFX_Move(p.x-2,p.y-162);
		GFX_Draw(p.x+l2+2,p.y-162);
		/* top margin text 1 */
		GFX_Move(p.x-2,p.y-30);
		GFX_Draw(p.x+l1+2,p.y-30);
		/* top margin text 2 */
		GFX_Move(p.x-2,p.y-126);
		GFX_Draw(p.x+l2+2,p.y-126);
		/* top and bottom system font margins */
		GFX_Move(p.x-2,p.y+2);
		GFX_Draw(p.x+l1+2,p.y+2);
		GFX_Move(p.x-2,p.y-94);
		GFX_Draw(p.x+l2+2,p.y-94);

		/* Display the fonts (if possible) */
		if ( preview_font != -1 )
		{
			e = Font_SetFont( preview_font );
			if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
			e = Wimp_SetFontColours( 7, 1 );
			if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
			e = Font_Paint( text1, 1<<4, p.x, p.y-64 +FONT_V_OFF);
			if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
			e = Font_Paint( text2, 1<<4, p.x, p.y-160 +FONT_V_OFF);
			if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
		}

		/* parts of the 3d border again in case the font overwrote it*/
		Wimp_SetColour(4);
		GFX_Move( rb.rect.min.x+2, rb.rect.min.y );
		GFX_Draw( rb.rect.max.x-2, rb.rect.min.y );
		GFX_Draw( rb.rect.max.x-2, rb.rect.max.y-2 );
		GFX_Move( rb.rect.min.x+4, rb.rect.min.y+2 );
		GFX_Draw( rb.rect.max.x-4, rb.rect.min.y+2 );
		GFX_Draw( rb.rect.max.x-4, rb.rect.max.y-4 );

		e = Wimp_GetRectangle( &rb, &more );
		if ( e ) { Msgs_ReportFatal(e->errnum,"err.swi",e->errmess); }
	}

	return TRUE;
}




static BOOL Hnd_ModeChange( event_pollblock *b, void *ref )
{
	font_changed( FALSE );
	return Screen_CacheModeInfo();
}


static void open_preview( void )
{
	if ( preview_window )
	{
		Window_BringToFront(preview_window);
	}
	else
	{
		char temp[256];
		int w;
		Msgs_Lookup("test.text1",temp,255);
		w = strlen(temp);
		Msgs_Lookup("test.text2",temp,255);
		if ( strlen(temp)>w ) { w = strlen(temp); }
		preview_window = Window_Create("preview",template_TITLEMIN);
		Window_SetExtent(preview_window,0,-192,w*16+36,0);
		Window_Show(preview_window,open_UNDERPOINTER);
		Event_Claim( event_REDRAW, preview_window, event_ANY, Hnd_RedrawP, 0 );
		Event_Claim( event_CLOSE, preview_window, event_ANY, Hnd_CloseP, 0 );
	}
}



/*--------------------------------------------------------------------------*/

/* We use this to differentiate between size/width selections */
static int size_menu_is_width;


static void open_font_size_menu( BOOL width )
{
	char menu_defn[128];
	char menu_title[12];
	size_menu_is_width = width;

	if ( size_menu ) { Menu_FullDispose(size_menu); size_menu=0; }

	if ( !Msgs_Lookup("font.sizes",menu_defn,128) )
		goto sm_err;
	if ( !Msgs_Lookup( width ? "font.width" : "font.size", menu_title, 12) )
		goto sm_err;
	size_menu = Menu_New( menu_title, menu_defn );
	if ( !size_menu )
		goto sm_err;

	Menu_PopUpAuto(size_menu);
	return;

sm_err:
	Msgs_Report(0,"err.sizemenu");
}



static char *sixteenths( int s )
{
	static char buffer[24];
	static char fracs[] = { '\0' , 188, 189, 190, '\0' };
	if ( s % 4 )
		sprintf(buffer,"%.2lf",(double)s/16.0);
	else
		sprintf(buffer,"%d%c",s/16,fracs[((s%16)+2)/4]);
	return buffer;
}



static void setup_main_win(void)
{
	int i;
	Icon_SetText(main_win,MAIN_FONTSIZE,sixteenths(font_size));
	Icon_SetText(main_win,MAIN_FONTWIDTH,sixteenths(font_width));
	if ( *font_name )
	{
		Icon_SetText(main_win,MAIN_FONTNAME,decode_font_name(font_name));
		Icon_Unshade(main_win,MAIN_TEST);
	}
	else
	{
		Icon_SetText(main_win,MAIN_FONTNAME,"<system font>");
		Icon_Shade(main_win,MAIN_TEST);
	}
	for ( i=0 ; i<3 ; i++ )
	{
		Icon_SetShade(main_win,MAIN_FONTSIZE+i,!*font_name);
		Icon_SetShade(main_win,MAIN_FONTWIDTH+i,!*font_name);
	}
	Icon_SetSelect(main_win,MAIN_3DDESK,desktop3d);
	Icon_SetSelect(main_win,MAIN_2DTOOLS,window2d);

	Icon_SetSelect(main_win,MAIN_TEXTURES,textures);
	Icon_SetSelect(main_win,MAIN_RISCPC,!musmus_texture && !tile_1_na);
	Icon_SetSelect(main_win,MAIN_MUSMUS,musmus_texture || tile_1_na);
	Icon_SetShade(main_win,MAIN_RISCPC,!textures || tile_1_na);
	Icon_SetShade(main_win,MAIN_MUSMUS,!textures);

	Icon_SetSelect(main_win,MAIN_DRAGASPRITE,dragasprite);
	Icon_SetSelect(main_win,MAIN_DITHER,dither);
	Icon_SetSelect(main_win,MAIN_TOGGLE,toggle);
	Icon_SetShade(main_win,MAIN_SOLID,!dragasprite);
	Icon_SetShade(main_win,MAIN_TRANSPARENT,!dragasprite);
	Icon_SetSelect(main_win,MAIN_SOLID,solid);
	Icon_SetSelect(main_win,MAIN_TRANSPARENT,!solid);
}





static BOOL Hnd_AuthOK( event_pollblock *pb, void *ref )
{
	Window_Delete(auth_win);
	auth_win = 0;
	return TRUE;
}



static BOOL Hnd_AuthClicked( event_pollblock *pb, void *ref )
{
	if ( !auth_win )
	{
		auth_win = Window_Create( "author", template_TITLEMIN );
		Event_Claim( event_CLICK, auth_win, AUTH_OK, Hnd_AuthOK, 0 );
	}
	Window_Show( auth_win, open_CENTERED );
	return TRUE;
}




static BOOL Hnd_MenuWarnInfo( event_pollblock *pb, void *ref )
{
	if ( !info_box )
	{
		info_box = Window_Create( "info", template_TITLEMIN );
		Icon_SetText(info_box,INFO_VERSION,version);
		Event_Claim(event_CLICK,info_box,INFO_AUTHOR,Hnd_AuthClicked,0);
	}
	Wimp_CreateSubMenu( (menu_ptr)info_box,
								pb->data.message.data.menuwarn.openpos.x,
								pb->data.message.data.menuwarn.openpos.y );
	return TRUE;
}


/* 'global' click handler.  Basically, any clicks not 'caught' by other	*/
/* handlers will drop through to here.  We use this soley to catch the	*/
/* Menu clicks that should open our standard menu.						*/
static BOOL Hnd_GClick( event_pollblock *pb, void *ref )
{
	if ( !pb->data.mouse.button.data.menu ) { return FALSE; }
	if ( !main_menu )
	{
		main_menu = Menu_New("Musmus",">Info,Quit");
		if ( !main_menu ) { Error_ReportFatal(0,"can't make menu"); }
		Menu_Warn(main_menu,0,TRUE,Hnd_MenuWarnInfo,0);
	}
	Menu_Show(main_menu,pb->data.mouse.pos.x-64,pb->data.mouse.pos.y+16);
	return TRUE;
}



static BOOL Hnd_MenuDel( event_pollblock *pb, void *ref )
{
	if (info_box) { Window_Delete(info_box); info_box = 0; }
	return FALSE;		/* always pass on */
}


static BOOL Hnd_MainClose( event_pollblock *pb, void *ref )
{
	Hnd_CloseP(pb,ref);		/* ensures that any Font is Lose-d */
	Event_CloseDown();
	exit(0);
	return TRUE;
}



static void do_fontmenu(void)
{
	Hourglass( TRUE );

	if ( !*font_name )
		font_menu = Menu_FontMenu3( TRUE, Menu_FontMenu_TICKSYSFONT );
	else
		font_menu = Menu_FontMenu3( TRUE, font_name );

	if ( !font_menu ) { Error_ReportFatal(0,"can't make font menu"); }
	Menu_PopUpAuto(font_menu);

	Hourglass( FALSE );
}


static void font_incdec( int *v, int up )
{
	if ( ShiftPressed() )
	{
		(*v) &= FONT_SIZE_MASK;
		(*v) += up ? FONT_SIZE_STEP : -FONT_SIZE_STEP;
	}
	else
	{
		(*v) &= ~3;
		(*v) += up ? 4 : -4;
	}
	if ( (*v)>24*16 ) { (*v)=24*16; }
	if ( (*v)<4*16 )  { (*v)=4*16; }
}


static BOOL Hnd_MainClick( event_pollblock *pb, void *ref )
{
	int adj = pb->data.mouse.button.data.adjust;
	int icn = pb->data.mouse.icon;

	if ( pb->data.mouse.button.data.menu )
	{
		switch (icn)
		{
			case MAIN_FONTNAME : case MAIN_FONTMENU :
			case MAIN_FONTSIZE : case MAIN_FONTWIDTH :
				break;
			default :
				return FALSE;
		}
	}
	switch ( icn )
	{
		case MAIN_FONTNAME : case MAIN_FONTMENU :
			do_fontmenu();
			break;
		case MAIN_FONTSIZE : case MAIN_FONTWIDTH :
			open_font_size_menu( icn==MAIN_FONTWIDTH );
			break;
		case MAIN_FONTSIZE+1 :
			font_incdec(&font_size,adj);
			Icon_SetText(main_win,MAIN_FONTSIZE,sixteenths(font_size));
			font_changed( TRUE );
			break;
		case MAIN_FONTSIZE+2 :
			font_incdec(&font_size,!adj);
			Icon_SetText(main_win,MAIN_FONTSIZE,sixteenths(font_size));
			font_changed( TRUE );
			break;
		case MAIN_FONTWIDTH+1 :
			font_incdec(&font_width,adj);
			Icon_SetText(main_win,MAIN_FONTWIDTH,sixteenths(font_width));
			font_changed( TRUE );
			break;
		case MAIN_FONTWIDTH+2 :
			font_incdec(&font_width,!adj);
			Icon_SetText(main_win,MAIN_FONTWIDTH,sixteenths(font_width));
			font_changed( TRUE );
			break;
		case MAIN_TEXTURES :
			textures = !textures;
			Icon_SetSelect(main_win,MAIN_TEXTURES,textures);
			Icon_SetShade(main_win,MAIN_RISCPC,!textures || tile_1_na);
			Icon_SetShade(main_win,MAIN_MUSMUS,!textures);
			break;
		case MAIN_RISCPC : case MAIN_MUSMUS :
			musmus_texture = icn==MAIN_MUSMUS;
			Icon_SetSelect(main_win,MAIN_RISCPC,!musmus_texture);
			Icon_SetSelect(main_win,MAIN_MUSMUS,musmus_texture);
			break;
		case MAIN_SOLID : case MAIN_TRANSPARENT :
			solid = icn==MAIN_SOLID;
			Icon_SetSelect(main_win,MAIN_SOLID,solid);
			Icon_SetSelect(main_win,MAIN_TRANSPARENT,!solid);
			break;
		case MAIN_3DDESK :
			Icon_SetSelect(main_win,MAIN_3DDESK,desktop3d=!desktop3d);
			break;
		case MAIN_DITHER :
			Icon_SetSelect(main_win,MAIN_DITHER,dither=!dither);
			break;
		case MAIN_TOGGLE :
			Icon_SetSelect(main_win,MAIN_TOGGLE,toggle=!toggle);
			break;
		case MAIN_DRAGASPRITE :
			Icon_SetSelect(main_win,MAIN_DRAGASPRITE,dragasprite=!dragasprite);
			Icon_SetShade(main_win,MAIN_SOLID,!dragasprite);
			Icon_SetShade(main_win,MAIN_TRANSPARENT,!dragasprite);
			break;
		case MAIN_2DTOOLS :
			Icon_SetSelect(main_win,MAIN_2DTOOLS,window2d=!window2d);
			break;
		case MAIN_TEST:
			open_preview();
			break;
		case MAIN_SET :
			if ( write_config() )
			{
				Wimp_SetMode(screen_mode);
				if ( !adj )
				{
					quit=TRUE;
					Hnd_CloseP(0,0);
					Window_Hide(main_win);
					query_box("all.done");
				}
			}
			break;
	}
	return TRUE;
}



static void font_selected( int selection[10] )
{
	char *fn;

	Hourglass( TRUE );

	if ( selection[0] )
		fn = Menu_FontMenuDecode3(selection);
	else
		fn="";
	strcpy(font_name,fn);
	if ( *fn )
		font_menu = Menu_FontMenu3( TRUE, fn );
	else
		font_menu = Menu_FontMenu3( TRUE, Menu_FontMenu_TICKSYSFONT ); 

	Hourglass( FALSE );

	font_changed( TRUE );
	setup_main_win();
}


static void size_selected( int selection[10] )
{
	char size[64];
	char tag[64];

	sprintf(tag,"font.size%d",selection[0]);
	if ( !Msgs_Lookup(tag,size,64) )
	{
		Msgs_Report(0,"err.sizesel",selection[0]);
		return;
	}

	if ( size_menu_is_width )
		font_width = atoi(size);
	else
		font_size = atoi(size);

	font_changed( TRUE );
	setup_main_win();
}



static BOOL Hnd_MenuSel( event_pollblock *pb, void *ref )
{
	mouse_block mb;
	if ( menu_currentopen == main_menu )
		quit = pb->data.selection[0]==1;

	else if ( menu_currentopen == font_menu )
		font_selected(pb->data.selection);

	else if ( menu_currentopen == size_menu )
		size_selected(pb->data.selection);

	Wimp_GetPointerInfo( &mb );
	if ( mb.button.data.adjust ) { Menu_ShowLast(); }

	return TRUE;
}



int main( void )
{
	debug = AltDown();
	Resource_InitialisePath("musmus");
	Event_Initialise("Musmus");
	EventMsg_Initialise();
	Screen_CacheModeInfo();
	if ( !Msgs_LoadFile("Messages") )
		Error_ReportFatal(0,"can't find the 'messages' file");
	resource_sprites = Sprite_LoadFile(choose_sprites("musmus:Sprites"));
	Template_Initialise();
	Template_UseSpriteArea(resource_sprites);
	Template_LoadFile("Templates");

	/* Install some application-wide handlers */
	Event_Claim( event_OPEN, event_ANY, event_ANY, Handler_OpenWindow, 0 );
	Event_Claim( event_CLOSE, event_ANY, event_ANY, Handler_CloseWindow, 0 );
	Event_Claim( event_CLICK, event_ANY, event_ANY, Hnd_GClick, 0 );
	Event_Claim( event_MENU, event_ANY, event_ANY, Hnd_MenuSel, 0 );
	EventMsg_Claim( message_MODECHANGE, event_ANY, Hnd_ModeChange, 0 );
	EventMsg_Claim( message_MENUSDELETED, event_ANY, Hnd_MenuDel, 0 );
	/* We'll give all the windows a 3d border.  When the preview window */
	/* is opened, it will pre-empt this general behaviour.				*/
	Event_Claim( event_REDRAW, event_ANY, event_ANY, Handler_Border, 0 );

	/* Make sure that it's safe for us to continue... */
	startup_tests();
	test_upgrade();

	/* Work out what state the machine is in at the moment */
	read_config();

	main_win = Window_Create("main",template_TITLEMIN);
	setup_main_win();
	Window_Show( main_win, open_CENTERED );
	Event_Claim( event_CLOSE, main_win, event_ANY, Hnd_MainClose, 0 );
	Event_Claim( event_CLICK, main_win, event_ANY, Hnd_MainClick, 0 );

	/* Do our funky stuff */
	while ( !quit ) { Event_Poll(); }

	/* All done now. */
	Hnd_CloseP(0,0);		/* make sure we release font handles */
	Event_CloseDown();
	return 0;
}


