/*
Auto:		smake ForceIcon
*/

/* $Revision Header built automatically *************** (do not edit) ************
**
** © Copyright by GuntherSoft
**
** File             : SnakeSYS:CPrgs/Utils/ForceIcon/Support.c
** Created on       : Friday, 22.10.93 16:38:41
** Created by       : Kai Iske
** Current revision : V1.0
**
**
** Purpose
** -------
**   - Support-Routines for ForceIcon
**
** Revision V1.0
** --------------
** created on Friday, 22.10.93 16:38:41  by  Kai Iske.   LogMessage :
**     --- Initial release ---
**
*********************************************************************************/



/**********************************************************************/
/*                         External variables                         */
/**********************************************************************/
extern struct	ExecBase	*SysBase;
extern struct	SignalSemaphore	MySemaphore;
extern struct	List		VolumeList;
extern struct	IClass		*GetFileClass;


/**********************************************************************/
/*                          Global variables                          */
/**********************************************************************/
static struct	RastPort	ComputeRPort;



/**********************************************************************/
/*                       Vars for Busy-Pointer                        */
/**********************************************************************/
static UWORD __chip BusyPtr[] =
{
	0x0000,0x0000,0x0400,0x07C0,0x0000,0x07C0,
	0x0100,0x0380,0x0000,0x07E0,0x07C0,0x1FF8,
	0x1FF0,0x3FEC,0x3FF8,0x7FDE,0x3FF8,0x7FBE,
	0x7FFC,0xFF7F,0x7EFC,0xFFFF,0x7FFC,0xFFFF,
	0x3FF8,0x7FFE,0x3FF8,0x7FFE,0x1FF0,0x3FFC,
	0x07C0,0x1FF8,0x0000,0x07E0,0x0000,0x0000
};



/**********************************************************************/
/*                          Calc X-Position                           */
/**********************************************************************/
UWORD ComputeX(UWORD value, UWORD FontX)
{
	return((UWORD)(((FontX * value) + 2) / 8));
}





/**********************************************************************/
/*                          Calc Y-Position                           */
/**********************************************************************/
UWORD ComputeY(UWORD value, UWORD FontY)
{
	return(( UWORD )((( FontY * value ) + 2 ) / 8 ));
}




/**********************************************************************/
/*                  Calc resolution and correct font                  */
/**********************************************************************/
void __stdargs ComputeFont(struct Screen *WorkScreen, UWORD width, UWORD height, struct TextAttr *Font, char *FontName, UWORD *OffX, UWORD *OffY, UWORD *FontX, UWORD *FontY)
{
		// Get Font-Structure

	strcpy(FontName, WorkScreen->RastPort.Font->tf_Message.mn_Node.ln_Name);

	Font->ta_Name	= FontName;
	Font->ta_YSize	= *FontY = WorkScreen->RastPort.Font->tf_YSize;
	Font->ta_Style	= FS_NORMAL;
	Font->ta_Flags	= 0;

	*FontX		= WorkScreen->RastPort.Font->tf_XSize;


		// Calc offsets

	*OffX = WorkScreen->WBorLeft;
	*OffY = WorkScreen->RastPort.TxHeight + WorkScreen->WBorTop + 1;


		// A Ok ???

	if(width && height)
	{
		if((ComputeX(width, *FontX) + *OffX + WorkScreen->WBorRight) > WorkScreen->Width)
			goto UseTopaz;
		if((ComputeY(height, *FontY) + *OffY + WorkScreen->WBorBottom) > WorkScreen->Height)
			goto UseTopaz;
	}
	return;

		// FallBack to Topaz8
UseTopaz:
	strcpy(FontName, "topaz.font");
	*FontX = *FontY = Font->ta_YSize = 8;
}




/**********************************************************************/
/*              Open a window with a background pattern               */
/**********************************************************************/
BOOL OpenWin(
			UWORD	Left,
			UWORD	Top,
			UWORD	Width,
			UWORD	Height,
			struct	Gadget		**BaseGadget,
			UWORD	NumGads,
			struct	_Object		**GetFile,
			struct	NewGadget	*NewGads,
			UWORD	*GTypes,
			ULONG	*GTags,
			struct	Gadget		**MyGads,
			struct	Window		**Handle,
			char	*Title,
			ULONG	IDCMP,
			ULONG	FLAGS,
			UWORD	MLeft,
			UWORD	MTop,
			UWORD	MWidth,
			UWORD	MHeight,
			struct	TextAttr	*WinTxtAttr,
			char			*WinTxtFontName,
			struct	VisualInfo	**VisInfo)
{
	UWORD Raster[4] =
	{
		0xAAAA,
		0x5555,
	};
	struct	Screen		*MyScreen;
	struct	Rectangle	ScrRec;
	struct	NewGadget	ng;
	struct	Gadget		*g;
	struct	TextFont	*MyFont = NULL;
	UWORD	lc, tc;
	UWORD	wleft, wtop, ww, wh, OffX, OffY, FontX, FontY,
		swidth, sheight;


	if(!(MyScreen = LockPubScreen("Workbench")))
		return(FALSE);

	if(!(*VisInfo = GetVisualInfo(MyScreen, TAG_DONE)))
		goto error;

		// Get Font and dimensions

	ComputeFont(MyScreen, Width, Height, WinTxtAttr, WinTxtFontName, &OffX, &OffY, &FontX, &FontY);


		// Set RastPort Font

	InitRastPort(&ComputeRPort);
	if(!(MyFont = OpenFont(WinTxtAttr)))
	{
		if(!(MyFont = OpenDiskFont(WinTxtAttr)))
			goto error;
	}
	SetFont(&ComputeRPort, MyFont);


		// Get size of window

	ww = ComputeX(Width, FontX);
	wh = ComputeY(Height, FontY);


		// Get info about Screenmode

	if(!QueryOverscan(GetVPModeID(&MyScreen->ViewPort), &ScrRec, OSCAN_TEXT))
		goto error;

		// Center window

	swidth	= min((ScrRec.MaxX + 1), MyScreen->Width);
	sheight	= min((ScrRec.MaxY + 1), MyScreen->Height);

	wleft	= ((swidth - ww - 1) >> 1) - ((MyScreen->LeftEdge < 0) ? MyScreen->LeftEdge : 0);
	wtop	= ((sheight - wh - 1) >> 1) - ((MyScreen->TopEdge < 0) ? MyScreen->TopEdge : 0);


		// Build GetFile image

	if(GetFile)
	{
		if(!(*GetFile = NewObject(GetFileClass, NULL, GT_VisualInfo, *VisInfo, IA_Width, ComputeX(20, FontX), IA_Height, ComputeY(14, FontY), TAG_DONE)))
			goto error;
	}

		// Create gadgets

	if(!(g = CreateContext(BaseGadget)))
		goto error;

	for(lc = 0, tc = 0; lc < NumGads; lc++)
	{
		CopyMem((char *)&NewGads[lc], (char *)&ng, (long)sizeof(struct NewGadget));

		ng.ng_VisualInfo	= *VisInfo;
		ng.ng_TextAttr		= WinTxtAttr;
		ng.ng_LeftEdge		= OffX + ComputeX(ng.ng_LeftEdge, FontX);
		ng.ng_TopEdge		= OffY + ComputeY(ng.ng_TopEdge, FontY);
		ng.ng_Width		= ComputeX(ng.ng_Width, FontX);
		ng.ng_Height		= ComputeY(ng.ng_Height, FontY);

			// Set gadget`s shortcut

		SetGadShortCut(GTypes[lc], &ng);

			// Check for ListView

		if(GTypes[lc] == LISTVIEW_KIND)
		{
			struct TagItem	*tmp;

			if(tmp = FindTagItem(GTLV_ShowSelected, (struct TagItem *)&GTags[tc]))
			{
				if(tmp->ti_Data)
					tmp->ti_Data = (ULONG)g;
				else
				{
						// With a normal ShowSelected,
						// adjust width according to version of OS

					if(((struct Library *)SysBase)->lib_Version < 39)
						ng.ng_Height	-= 8;
				}
			}
		}

			// Create gadget

		MyGads[lc] = g = CreateGadgetA(GTypes[lc], g, &ng, (struct TagItem *)&GTags[tc]);

			// Error ???

		if(!g)
			goto error;

			// Set GetFile image

		if(GTypes[lc] == GENERIC_KIND && GetFile)
		{
			struct	TagItem	*tmp;
			BOOL	Disabled = FALSE;

			if((tmp = FindTagItem(GA_Disabled, (struct TagItem *)&GTags[tc])))
				Disabled = (BOOL)tmp->ti_Data;

			g->Flags		|= GFLG_GADGIMAGE | GFLG_GADGHIMAGE | ((Disabled) ? GFLG_DISABLED : 0);
			g->Activation		|= GACT_RELVERIFY;
			g->GadgetType		|= GTYP_BOOLGADGET;
			g->GadgetRender		= (APTR)*GetFile;
			g->SelectRender		= (APTR)*GetFile;
		}

			// Patch String/Integer Gadgets

		if(GTypes[lc] == STRING_KIND || GTypes[lc] == INTEGER_KIND)
		{
			((struct StringInfo *)g->SpecialInfo)->Extension->ActivePens[0] = 1;
			((struct StringInfo *)g->SpecialInfo)->Extension->ActivePens[1] = 2;
		}

		while(GTags[tc])
			tc += 2;
		tc++;
	}

		// Close Font

	CloseFont(MyFont);

		// Open window

	if(!(*Handle = OpenWindowTags(NULL,
		WA_Left,		wleft,
		WA_Top,			wtop,
		WA_Width,		ww + OffX + MyScreen->WBorRight,
		WA_Height,		wh + OffY + MyScreen->WBorBottom,
		WA_IDCMP,		IDCMP,
		WA_Flags,		FLAGS,
		WA_Title,		Title,
		WA_CustomScreen,	MyScreen,
	TAG_DONE)))
		goto error;

		// Clear userdata-field

	(*Handle)->UserData	= NULL;

		// Unlock Pub screen

	UnlockPubScreen(NULL, MyScreen);

	if(MLeft && MTop && MWidth && MHeight)
	{
			// Draw Raster

		SetAPen((*Handle)->RPort, 2);
		SetAfPt((*Handle)->RPort, Raster, 1);
		RectFill((*Handle)->RPort, (*Handle)->BorderLeft, (*Handle)->BorderTop, (*Handle)->Width - (*Handle)->BorderRight - 1, (*Handle)->Height - (*Handle)->BorderBottom - 1);
		SetAfPt((*Handle)->RPort, NULL, 0);

			// Clear gadget areas and draw bevelbox

		SetAPen((*Handle)->RPort, 0);

		wleft	= OffX + ComputeX(MLeft, FontX);
		wtop	= OffY + ComputeY(MTop, FontY);
		RectFill((*Handle)->RPort, wleft, wtop, wleft + ComputeX(MWidth, FontX) - 1, wtop + ComputeY(MHeight, FontY) - 1);
		DrawBevelBox((*Handle)->RPort, wleft, wtop,
			ComputeX(MWidth, FontX),
			ComputeY(MHeight, FontY),
			GT_VisualInfo, *VisInfo, GTBB_Recessed, TRUE,
		TAG_DONE);
	}

		// Add gadgets and display them

	AddGList((*Handle), *BaseGadget, -1, -1, NULL);
	RefreshGadgets(*BaseGadget, (*Handle), NULL);

	GT_RefreshWindow((*Handle), NULL );
	return(TRUE);

error:
	if(MyScreen)
		UnlockPubScreen(NULL, MyScreen);
	if(MyFont)
		CloseFont(MyFont);
	return(FALSE);

}





/**********************************************************************/
/*                        Close a window again                        */
/**********************************************************************/
void CloseWin(struct Window **Handle, struct Gadget **MyGad, struct VisualInfo **VisInfo, struct _Object **GetFile)
{
	if(*Handle)
	{
		CloseWindow((*Handle));
		*Handle = NULL;
	}

	if(*MyGad)
	{
		FreeGadgets((*MyGad));
		*MyGad = NULL;
	}

	if(*VisInfo)
	{
		FreeVisualInfo(*VisInfo);
		*VisInfo = NULL;
	}

	if(GetFile && *GetFile)
	{
		DisposeObject(*GetFile);
		*GetFile = NULL;
	}
}





/**********************************************************************/
/*                      Set a gadget`s shortcut                       */
/**********************************************************************/
void SetGadShortCut(UWORD Type, struct NewGadget *NewGad)
{
	char *UnderScore, MyChar;
	ULONG EventType = 0;

		// Get char of ShortCut

	if(NewGad->ng_GadgetText && (UnderScore = (char *)strchr(NewGad->ng_GadgetText, '_')))
	{
		MyChar = *(UnderScore + 1);
		NewGad->ng_UserData = (void *)ToUpper(MyChar);
	}

		// Set type of event suited for Keystroke activation

	switch(Type)
	{
		case BUTTON_KIND :
		case CYCLE_KIND :
		case LISTVIEW_KIND :
		case CHECKBOX_KIND :
		{
			EventType = IDCMP_GADGETUP;
			break;
		}
		case STRING_KIND :
		case INTEGER_KIND :
		{
			EventType = IDCMP_GADGETDOWN;
			break;
		}
	}

	if(EventType)
		NewGad->ng_UserData = (void *)((ULONG)NewGad->ng_UserData | (EventType << 8));
}





/**********************************************************************/
/*                    Get device and volume lists                     */
/**********************************************************************/
BOOL GetDevVolList(struct List *VolList)
{
	NewList(VolList);
	VolList->lh_Type = 0;

	if(GetDosEntries(VolList, LDF_DEVICES))
	{
		if(GetDosEntries(VolList, LDF_VOLUMES))
		{
			SortList(VolList, FALSE);
			return(TRUE);
		}
	}

	return(FALSE);
}



/**********************************************************************/
/*                     Collect available volumes                      */
/**********************************************************************/
BOOL GetDosEntries(struct List *VolList, ULONG Mode)
{
	struct	DosList		*DList;
	struct	VolEntry	*NewEntry;
	BOOL	RetVal		= FALSE;

		// Lock DOS-List of Volumes

	if((DList = LockDosList(Mode|LDF_READ)))
	{
			// Loop for all entries

		while(DList)
		{
				// Get next entry

			if(!(DList = NextDosEntry(DList, Mode|LDF_READ)))
				RetVal = TRUE;
			else
			{
				BOOL	DoGet = TRUE;

				if(DList->dol_Type == DLT_DEVICE)
				{
					struct	FileSysStartupMsg *FSSM = (struct FileSysStartupMsg *)BADDR(DList->dol_misc.dol_handler.dol_Startup);
					DoGet = FALSE;

					if(FSSM && TypeOfMem(FSSM) && TypeOfMem(BADDR(FSSM->fssm_Device)) && TypeOfMem(BADDR(FSSM->fssm_Environ)))
					{
						if(*((char *)BADDR(FSSM->fssm_Device)) != 255)
						{
							struct	DosEnvec	*DE = (struct DosEnvec *)BADDR(FSSM->fssm_Environ);

							if(DE && TypeOfMem(DE))
							{
								if(DE->de_Surfaces && DE->de_BlocksPerTrack)
									DoGet = TRUE;
							}
						}
					}
				}

				if(DoGet)
				{
						// Alloc memory for new entry

					if((NewEntry = AllocVec(sizeof(struct VolEntry), MEMF_CLEAR)))
					{
							// Add to list

						AddTail(VolList, (struct Node *)NewEntry);
						NewEntry->Link.ln_Name	= NewEntry->VolName;
						NewEntry->Link.ln_Type	= Mode;
						VolList->lh_Type++;

						strcpy(NewEntry->VolName, ((char *)BADDR(DList->dol_Name) + 1));
					}
					else
						DList = NULL;
				}
			}
		}

			// Unlock DOS-List again

		UnLockDosList(Mode|LDF_READ);
	}

	if(!RetVal)
		DisplayError(ERR_NOTALL, NULL);

	return(RetVal);
}







/**********************************************************************/
/*                        Release Volume-Nodes                        */
/**********************************************************************/
void FreeDevVolList(struct List *VolList)
{
	struct	Node	*DelNode;

	while((DelNode = RemHead(VolList)))
		FreeVec(DelNode);
}






/**********************************************************************/
/*                     Check for gadget shortcuts                     */
/**********************************************************************/
void CheckKeys(ULONG *MsgClass, UWORD *MsgCode, UWORD *GadID, BOOL *KeyUse, struct Gadget **MsgGad, struct Gadget **EditGads, UWORD NumGads)
{
	register int i;

		// Key pressed ???

	if(*MsgClass == IDCMP_VANILLAKEY)
	{
			// Key released ???

		if(!(*MsgCode & IECODE_UP_PREFIX))
		{
				// ESC hit ??? -> Return CLOSE WINDOW

			if(*MsgCode == ESCKEY)
				*MsgClass	= IDCMP_CLOSEWINDOW;

				// On Return, search for the first String/Integer gadget

			else if(*MsgCode == 0x0d)
			{
					// Search for gadget

				for(i = 0; i < NumGads; i++)
				{
						// This is the one

					if((EditGads[i]->GadgetType & GTYP_STRGADGET) && !(EditGads[i]->Flags & GFLG_DISABLED))
					{
							// Set flags and vars

						*MsgGad		= EditGads[i];
						*MsgClass	= IDCMP_ACTSTRGAD;
						*KeyUse		= TRUE;
						break;
					}
				}
			}
			else
			{
					// Get Char hit

				*MsgCode = (UWORD)ToUpper((char)*MsgCode);

					// Search for suited gadget

				for(i = 0; i < NumGads; i++)
				{
					if(((ULONG)EditGads[i]->UserData & 0x000000ff) == (ULONG)*MsgCode)
					{
							// Set flags

						*MsgGad		= EditGads[i];
						*GadID		= (*MsgGad)->GadgetID;
						*MsgClass	= ((ULONG)(*MsgGad)->UserData & 0x0000ff00) >> 8;
						*KeyUse		= TRUE;
						break;
					}
				}
			}
		}
	}
	else
		*KeyUse = FALSE;
}





/**********************************************************************/
/*                      Handle a listview gadget                      */
/**********************************************************************/
ULONG HandleListViewGad(struct Gadget *Gad, struct Window *MsgWin, BOOL KeyUse, UWORD MsgCode, UWORD MsgQual, LONG Val, ULONG Min, ULONG Max)
{
	if(KeyUse)
	{
			// Key hit

		if(MsgQual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
		{
				// On SHIFT move up

			if((Val != Min) && (Val != -1))
				Val--;
		}
		else
		{
				// On NON-SHIFT move down

			if(Val != Max)
				Val++;
		}

			// Set gadget

		if(Val != -1)
		{
			GT_SetGadgetAttrs(Gad, MsgWin, NULL,
				GTLV_Selected,	Val,
				GTLV_Top,	Val,
			TAG_DONE);
		}
	}
	else
			// Otherwiese simply get Message-Code

		Val = MsgCode;


	return((ULONG)Val);
}




/**********************************************************************/
/*                       Handle a cycle gadget                        */
/**********************************************************************/
ULONG HandleCycleGad(struct Gadget *Gad, struct Window *MsgWin, BOOL KeyUse, UWORD MsgCode, UWORD MsgQual, ULONG Val, ULONG Min, ULONG Max)
{
	if(KeyUse)
	{
			// Key hit

		if(MsgQual & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
		{
				// On SHIFT move upward, on minimum jump to highest entry

			if(Val == Min)
				Val = Max;
			else
				Val--;
		}
		else
		{
				// On NON-SHIFT move downward, on maximum jump to lowest entry

			if(Val == Max)
				Val = Min;
			else
				Val++;
		}

			// Set gadget

		GT_SetGadgetAttrs(Gad, MsgWin, NULL,
			GTCY_Active, Val,
		TAG_DONE);
	}
	else
			// Otherwise simply get MsgCode

		Val = MsgCode;


	return(Val);
}




/**********************************************************************/
/*                      Get an entry from a list                      */
/**********************************************************************/
APTR GetListEntry(struct List *List, WORD EntryNum)
{
	struct	Node	*ThisEntry = NULL, *CheckEntry;

		// Search list for entry

	if(!IsListEmpty((struct List *)List) && EntryNum >= 0)
	{
		CheckEntry = List->lh_Head;

		while(CheckEntry->ln_Succ && EntryNum)
		{
			CheckEntry	= CheckEntry->ln_Succ;
			EntryNum--;
		}

		if(!EntryNum)
			ThisEntry	= CheckEntry;
	}

	return(ThisEntry);
}




/**********************************************************************/
/*                        Set a window to Busy                        */
/**********************************************************************/
void BusyWindow(struct Window *Window, struct Requester *MyReq)
{
	if(Window)
	{
			// Clear Requester structure

		setmem((void *)MyReq, sizeof(struct Requester), 0);

			// Open Requester and store address within UserData

		Window->UserData = (char *)Request(MyReq, Window);

			// Set Pointer

		if(SysBase->LibNode.lib_Version < 39)
			SetPointer(Window, &BusyPtr[0],  16, 16, -6, 0);
		else
			SetWindowPointer(Window, WA_BusyPointer, TRUE, TAG_DONE);
	}
}




/**********************************************************************/
/*                          UnBusy a window                           */
/**********************************************************************/
void UnBusyWindow(struct Window *Window, struct Requester *MyReq)
{
	if(Window)
	{
			// Close Requester

		if(Window->UserData)
			EndRequest(MyReq, Window);
		Window->UserData = NULL;

			// Reset Pointer

		if(SysBase->LibNode.lib_Version < 39)
			ClearPointer(Window);
		else
			SetWindowPointer(Window, TAG_DONE);
	}
}







/**********************************************************************/
/*                       Save Prefs to disk/env                       */
/**********************************************************************/
BOOL SavePrefs(BOOL EnvMode)
{
		// On ENV: mode, simply save to ENV: only

	if(DoSavePrefs("ENV:ForceIcon_prefs.iff"))
	{
			// Otherwise write to envarc: as well

		if(!EnvMode)
			return(DoSavePrefs("ENVARC:ForceIcon_prefs.iff"));
		else
			return(TRUE);
	}
	return(FALSE);
}
BOOL DoSavePrefs(char *PrefsName)
{
	struct	IFFHandle	*PrefsHandle;
	LONG	Error;
	BOOL	GoOn = FALSE;
	UWORD	VersChunk[] =
	{
		VERNUM,
		REVNUM
	};

		// Get handle for IFF

	if((PrefsHandle = AllocIFF()))
	{
			// Open file for save

		if((PrefsHandle->iff_Stream = Open(PrefsName, MODE_NEWFILE)))
		{
				// Init Handle

			InitIFFasDOS(PrefsHandle);

				// Open Handle

			if(!(Error = OpenIFF(PrefsHandle, IFFF_WRITE)))
			{
					// Write FORM chunk

				if(!(Error = PushChunk(PrefsHandle, 'FOIC', 'FORM', IFFSIZE_UNKNOWN)))
				{
						// Write version chunk

					if(!(Error = PushChunk(PrefsHandle, 'FOIC', 'VERS', IFFSIZE_UNKNOWN)))
					{
						if((Error = WriteChunkBytes(PrefsHandle, &VersChunk[0], (sizeof(UWORD) * 2))) == (sizeof(UWORD) * 2))
							Error = PopChunk(PrefsHandle);
						else
							Error = IoErr();
					}

						// Write Prefs chunk

					if(!Error && !(Error = PushChunk(PrefsHandle, 'FOIC', 'PREF', IFFSIZE_UNKNOWN)))
					{
						struct	VolEntry	*ThisEntry	= (struct VolEntry *)VolumeList.lh_Head;
						UWORD	NumEntries			= VolumeList.lh_Type;
						BOOL	NoErr = TRUE;

								// Write all entries of volume list

						if((Error = WriteChunkBytes(PrefsHandle, &NumEntries, sizeof(UWORD))) == sizeof(UWORD))
						{
							while(NumEntries-- && NoErr)
							{
								UWORD	EntryType = ThisEntry->Link.ln_Type;

								if((Error = WriteChunkBytes(PrefsHandle, &EntryType, sizeof(UWORD))) == sizeof(UWORD))
								{
									if((Error = WriteChunkBytes(PrefsHandle, &ThisEntry->VolName, 130)) == 130)
									{
										if((Error = WriteChunkBytes(PrefsHandle, &ThisEntry->IconName, 256)) == 256)
										{
											if((Error = WriteChunkBytes(PrefsHandle, &ThisEntry->Left, (sizeof(UWORD) * 4))) != (sizeof(UWORD) * 4))
												NoErr = FALSE;
										}
									}
								}

								ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
							}

							if(NoErr)
							{
								if(!(Error = PopChunk(PrefsHandle)))
									GoOn = TRUE;
							}
						}
					}
				}

				if((Error = PopChunk(PrefsHandle)))
					GoOn = FALSE;

				CloseIFF(PrefsHandle);
			}

			Close(PrefsHandle->iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(PrefsHandle);
	}
	else
		Error = ERR_NOMEM;

	if(!GoOn)
		DisplayError(Error, (ULONG)PrefsName, NULL);

	return(GoOn);
}







/**********************************************************************/
/*                          Load in settings                          */
/**********************************************************************/
void LoadPrefs(void)
{
		// Try env: first, then envarc:
	if(!DoLoadPrefs("ENV:ForceIcon_prefs.iff"))
		DoLoadPrefs("ENVARC:ForceIcon_prefs.iff");
}
BOOL DoLoadPrefs(char *PrefsName)
{
	struct	IFFHandle	*PrefsHandle;
	struct	StoredProperty	*SP;
	UWORD	*VersCheck;
	LONG	Error;
	BOOL	GoOn = FALSE;

		// Initialize Lists first

	NewList(&VolumeList);
	VolumeList.lh_Type = 0;

		// Get Prefs Handle

	if((PrefsHandle = AllocIFF()))
	{
			// Open file

		if((PrefsHandle->iff_Stream = Open(PrefsName, MODE_OLDFILE)))
		{
				// Init handle

			InitIFFasDOS(PrefsHandle);

				// Open Handle

			if(!(Error = OpenIFF(PrefsHandle, IFFF_READ)))
			{
					// Search for version chunk

				if(!(Error = PropChunk(PrefsHandle, 'FOIC', 'VERS')))
				{
						// Stop at prefs

					if(!(Error = StopChunk(PrefsHandle, 'FOIC', 'PREF')))
					{
							// Start parsing

						if(!(Error = ParseIFF(PrefsHandle, IFFPARSE_SCAN)))
						{
								// Try to find version chunk

							if((SP = FindProp(PrefsHandle, 'FOIC', 'VERS')))
							{
								VersCheck = (UWORD *)SP->sp_Data;

									// Check Version number

								if(((*VersCheck) <= VERNUM) && ((*(VersCheck+1)) <= REVNUM))
								{
									struct	VolEntry	*ThisEntry;
									UWORD	NumEntries, EntryType;
									BOOL	NoErr = TRUE;

										// Read in prefs

									if((Error = ReadChunkBytes(PrefsHandle, &NumEntries, sizeof(UWORD))) == sizeof(UWORD))
									{
										VolumeList.lh_Type = NumEntries;

										while(NumEntries-- && NoErr)
										{
											if((ThisEntry = AllocVec(sizeof(struct VolEntry), MEMF_CLEAR)))
											{
												AddTail(&VolumeList, (struct Node *)ThisEntry);
												ThisEntry->Link.ln_Name = ThisEntry->VolName;

												if((Error = ReadChunkBytes(PrefsHandle, &EntryType, sizeof(UWORD))) == sizeof(UWORD))
												{
													ThisEntry->Link.ln_Type = EntryType;

													if((Error = ReadChunkBytes(PrefsHandle, &ThisEntry->VolName, 130)) == 130)
													{
														if((Error = ReadChunkBytes(PrefsHandle, &ThisEntry->IconName, 256)) == 256)
														{
															if((Error = ReadChunkBytes(PrefsHandle, &ThisEntry->Left, (sizeof(UWORD) * 4))) != (sizeof(UWORD) * 4))
																NoErr = FALSE;
														}
													}
												}
											}
											else
												NoErr = FALSE;
										}
										GoOn = NoErr;
									}

									if(!NoErr)
										Error = IoErr();
								}
							}
						}
					}
				}
				CloseIFF(PrefsHandle);
			}

			Close(PrefsHandle->iff_Stream);
		}
		else
			Error = IoErr();

		FreeIFF(PrefsHandle);
	}
	else
		Error = ERR_NOMEM;

	if(!GoOn && Error != ERROR_OBJECT_NOT_FOUND)
		DisplayError(Error, (ULONG)PrefsName);


	return(GoOn);
}







/**********************************************************************/
/*                           Get a filename                           */
/**********************************************************************/
BOOL GetFileName(struct Window *Window, char *Title, char *FileName)
{
	struct	Rectangle	ScrRec;
	struct	FileRequester	*FileReq;
	char	Drawer[256],
		File[256];
	UWORD	Left, Top, Width, Height, i;
	BOOL	Result = FALSE;

	if(QueryOverscan(GetVPModeID(&Window->WScreen->ViewPort), &ScrRec, OSCAN_TEXT))
	{
		Width	= ((ScrRec.MaxX - ScrRec.MinX + 1) * 45) / 100;
		Height	= ((ScrRec.MaxY - ScrRec.MinY + 1) * 8) / 10;
		Left	= (((ScrRec.MaxX + 1) - Width) >> 1) - Window->WScreen->LeftEdge;
		Top	= (((ScrRec.MaxY + 1) - Height) >> 1) - Window->WScreen->TopEdge;

			// Get initial path

		if(PathPart(FileName) != (UBYTE *)&FileName[0])
		{
			for(i = 0; i < 256; i++)
				Drawer[i] = '\0';
			strncpy(Drawer, FileName, (PathPart(FileName) - FileName));
		}
		else
			strcpy(Drawer, "");

			// Get FileName

		strcpy(File, FilePart(FileName));

		if((FileReq = AllocAslRequestTags(ASL_FileRequest,
			ASLFR_Screen,		Window->WScreen,
			ASLFR_Window,		Window,
			ASLFR_PrivateIDCMP,	TRUE,
			ASLFR_SleepWindow, 	TRUE,
			ASLFR_TitleText,	Title,
			ASLFR_InitialDrawer,	(ULONG)Drawer,
			ASLFR_InitialFile,	(ULONG)File,
			ASLFR_InitialLeftEdge,	Left,
			ASLFR_InitialTopEdge,	Top,
			ASLFR_InitialWidth,	Width,
			ASLFR_InitialHeight,	Height,
			ASLFR_InitialPattern,	"#?.info",
		TAG_DONE)))
		{
			if(AslRequest(FileReq, NULL) && (strlen(FileReq->fr_File)))
			{
					// Remove filetypes

				strcpy(FileName, "");

				AddPart(FileName, FileReq->fr_Drawer, 256);
				AddPart(FileName, FileReq->fr_File, 256);

				Result = TRUE;
			}

			FreeAslRequest(FileReq);
		}
	}

	return(Result);
}



/**********************************************************************/
/*        Check for existance of a volume within the user list        */
/**********************************************************************/
BOOL CheckExists(char *Name)
{
	BOOL	RetVal = FALSE;

	ObtainSemaphore(&MySemaphore);

	if(!IsListEmpty(&VolumeList))
	{
		struct	VolEntry	*ThisEntry	= (struct VolEntry *)VolumeList.lh_Head;

		do
		{
			if(!stricmp(ThisEntry->VolName, Name))
				RetVal = TRUE;

			ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
		} while(!RetVal && ThisEntry->Link.ln_Succ);
	}

	ReleaseSemaphore(&MySemaphore);

	return(RetVal);
}




/**********************************************************************/
/*             Sort the complete list of devices/volumes              */
/**********************************************************************/
void SortList(struct List *VolList, BOOL DisplayType)
{
	UWORD	First, Last;

	if(DisplayType)
	{
		First	= LDF_VOLUMES;
		Last	= LDF_DEVICES;
	}
	else
	{
		First	= LDF_DEVICES;
		Last	= LDF_VOLUMES;
	}

		// Sort partial lists within one list

	if(!IsListEmpty(VolList))
	{
		struct	VolEntry	*ThisEntry	= (struct VolEntry *)VolList->lh_Head;
		UWORD	NumEntries			= VolList->lh_Type;
		UWORD	Left = 0, Right = 0;

			// Find boundaries of first type of entries

		while(ThisEntry->Link.ln_Type == First && NumEntries)
		{
			Right++;
			NumEntries--;
			ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
		}

			// Sort`em

		if(Left < Right)
		{
			SortPartialList(VolList, Left, Right);
			Left = Right;
		}

			// Look for second type of entries

		while(ThisEntry->Link.ln_Type == Last && NumEntries)
		{
			Right++;
			NumEntries--;
			ThisEntry = (struct VolEntry *)ThisEntry->Link.ln_Succ;
		}

			// Sort`em

		if(Left < Right)
			SortPartialList(VolList, Left, Right);
	}
}



/**********************************************************************/
/*            Sort partial list, either devices or volumes            */
/**********************************************************************/
void SortPartialList(struct List *VolList, UWORD Left, UWORD Right)
{
	UWORD	i, j;

		// This is a simply Insertion Sort
		// I don`t think that there will be too many entries,
		// so this algorithm will do it. (IMHO)

	for(i = Left + 1; i < Right; i++)
	{
		struct	VolEntry	Spare, *CheckEntry;

			j = i;

			Spare		= *((struct VolEntry *)GetListEntry(VolList, i));
			CheckEntry	= (struct VolEntry *)GetListEntry(VolList, j - 1);

			while(stricmp(CheckEntry->VolName, Spare.VolName) > 0 && j > Left)
			{
				struct	VolEntry	*RightEntry = (struct VolEntry *)CheckEntry->Link.ln_Succ;

				strcpy(RightEntry->VolName, CheckEntry->VolName);
				strcpy(RightEntry->IconName, CheckEntry->IconName);
				RightEntry->Left	= CheckEntry->Left;
				RightEntry->Top		= CheckEntry->Top;
				RightEntry->UseAlt	= CheckEntry->UseAlt;

				j--;
				CheckEntry = (struct VolEntry *)CheckEntry->Link.ln_Pred;
			}

			CheckEntry = (struct VolEntry *)GetListEntry(VolList, j);
			strcpy(CheckEntry->VolName, Spare.VolName);
			strcpy(CheckEntry->IconName, Spare.IconName);
			CheckEntry->Left	= Spare.Left;
			CheckEntry->Top		= Spare.Top;
			CheckEntry->UseAlt	= Spare.UseAlt;
	}
}
