/*
 * $Source: $
 * $Revision: $
 * $Date: $
 * $State: $
 * $Author: $
 *
 *
 * $Log: $
 *
 */

/*-----------------------------------------------------------------------------------------
#
#	Apple Macintosh Developer Technical Support
#
#	Collection of Utilities for DTS Sample code
#
#	Program:	Utilities.c.o
#	File:		Utilities.c	-	C Source
#
#	Copyright © 1988-1990 Apple Computer, Inc.
#	All rights reserved.
#
-----------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------------------
	#include files
-----------------------------------------------------------------------------------------*/
#ifdef applec

#ifndef __CONTROLS__
#include <Controls.h>
#endif

#ifndef __DESK__
#include <Desk.h>
#endif

#ifndef __EVENTS__
#include <Events.h>
#endif

#ifndef __FIXMATH__
#include <FixMath.h>
#endif

#ifndef __FONTS__
#include <Fonts.h>
#endif

#ifndef __MENUS__
#include <Menus.h>
#endif

#ifndef __OSEVENTS__
#include <OSEvents.h>
#endif

#ifndef __PACKAGES__
#include <Packages.h>
#endif

#ifndef __RESOURCES__
#include <Resources.h>
#endif

#ifndef __SCRIPT__
#include <Script.h>
#endif

#ifndef __SEGLOAD__
#include <SegLoad.h>
#endif

#ifndef __STRING__
#include <String.h>
#endif

#ifndef __TEXTEDIT__
#include <TextEdit.h>
#endif

#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif

#ifndef __TRAPS__
#include <Traps.h>
#endif

#endif
#include <stdio.h>
#include "Utilities.h"

/*-----------------------------------------------------------------------------------------
	Global variables -- See Utilities.h for more explanation
-----------------------------------------------------------------------------------------*/
int				gMachineType;			/* which machine this is */
int				gSystemVersion;			/* System version number */
int				gProcessorType;			/* which CPU this is */
Boolean			gHasFPU;				/* true if machine has an FPU */
int				gQDVersion;				/* major QD version #; 0 for original,
													1 for color QD, 2 for 32-bit QD */
int				gKeyboardType;			/* which type of keyboard is present */
int				gAppleTalkVersion;		/* AppleTalk version number */
Boolean			gHasPMMU;				/* true if machine has a PMMU or equivalent */
int				gAUXVersion;			/* major A/UX version number (0 if not present) */

Boolean			gHasWaitNextEvent;
short			gAppResRef;
Boolean			gInBackground;
Str255			gAppName;
OSType			gSignature = '????';
Boolean			gUtilitiesInited;


/*-----------------------------------------------------------------------------------------*/
/* Given an Alert ID, this routine will center the alertÕs rectangle before
  showing it on the main screen. This follows the Apple Human Interface
  Guidelines for where to place a centered window on the screen. If the Alert
  is closely associated with another window, considerations should be given to
  where the window is located. If this other window is on a screen other than
  the main monitor, then it would be best to center the Alert on that other
  monitor. */

#pragma segment UtilMain
short	CenteredAlert (short alertID)
{
	AlertTHndl			alertHandle;
	short				itemHit;

	alertHandle = (AlertTHndl)GetAppResource('ALRT',alertID);
	if (alertHandle) {
		LockHandleHigh((Handle)alertHandle);
		CenterWindowRect(dBoxProc, &((**alertHandle).boundsRect));
#ifdef applec
		itemHit = Alert(alertID, (ModalFilterProcPtr) nil);
#else
		itemHit = Alert(alertID,  nil);
#endif

		HUnlock ((Handle)alertHandle);
		return (itemHit);
	}
}

/*-----------------------------------------------------------------------------------------*/
#pragma segment UtilMain

void	LockHandleHigh (Handle theHandle)
{
	MoveHHi(theHandle);
	HLock(theHandle);
}

/*-----------------------------------------------------------------------------------------*/
#pragma segment UtilMain
void	CenterWindowRect (short procID, Rect *theRect)
{
	Rect	screenRect;

#ifdef applec
	screenRect = qd.screenBits.bounds;
#else
	screenRect = screenBits.bounds;
#endif
	screenRect.top += GetMBarHeight();
	CenterWindowRectTo(procID, screenRect, theRect);
}


/*-----------------------------------------------------------------------------------------*/
/* Given a windowÕs portRect, this routine will center the rectangle in the
  specified bounding rectangle. It follows the Apple Human Interface
  Guidelines for where to place a window centered on the screen. That is,
  1/3rd of the desktop shows above the window and 2/3rds below it. It returns
  a new rectangle set to the centered position. The top and left of this
  rectangle can be used with MoveWindow or NewWindow.

  WARNING: This routine may move or purge memory. */

#pragma segment UtilMain
void	CenterWindowRectTo (short procID, Rect screenRect, Rect *theRect)
{
	Point			windowSize;
	Rect			strucRect, newStrucRect;

	GetWindowStrucRect(procID, *theRect, &strucRect);
	newStrucRect = strucRect;
	PositionTwoRects(screenRect, &newStrucRect, FixRatio (1, 2), FixRatio (1, 3));
	windowSize = BotRight(*theRect);
	SubPt(TopLeft(*theRect), &windowSize);
	(*theRect).top = newStrucRect.top + ((*theRect).top - strucRect.top);
	(*theRect).left = newStrucRect.left + ((*theRect).left - strucRect.left);
	(*theRect).bottom = (*theRect).top + windowSize.v;
	(*theRect).right = (*theRect).left + windowSize.h;
}

/*-----------------------------------------------------------------------------------------*/
/* This procedure is used to get the rectangle that surrounds the entire structure of a
  window, given the rectangle that would be used for the portRect. It does this by
  temporarily creating a window way offscreen, and getting the rgnBBox of its strucRgn.
  The window is disposed of afterwards, and the port set back to the original port. */

#pragma segment UtilMain
void	GetWindowStrucRect(short procID, Rect boundsRect, Rect *strucRect)
{
#define kOffscreenLoc 0x4000

	GrafPtr			oldPort;
	WindowPtr		tempWindow;
	Point			offsetAmount;

	GetPort(&oldPort);
	SETPT(&offsetAmount, kOffscreenLoc, kOffscreenLoc);
	SubPt(TopLeft(boundsRect), &offsetAmount);
	OffsetRect(&boundsRect, offsetAmount.h, offsetAmount.v);
	tempWindow = NewWindow(nil, &boundsRect, '', true, procID, (WindowPtr)nil, true, 0);
	(*strucRect) = (**(*(WindowPeek)tempWindow).strucRgn).rgnBBox;
	DisposeWindow(tempWindow);
	OffsetRect(strucRect, -offsetAmount.h, -offsetAmount.v);
	SetPort(oldPort);
}

/*-----------------------------------------------------------------------------------------*/
/* Given two rectangles, this routine positions the second within the first one
  so that it maintains the spacing specified by the horzRatio and vertRatio
  parameters. In other words, to center an inner rectangle hoizontally, but
  have its center be 1/3 from the top of the outer rectangle, call this
  routine with horzRatio = FixRatio (1, 2), vertRatio = FixRatio (1, 3).  We use
  Fixed rather than floating point to avoid complications when mixing MC68881/non-MC68881
  versions of Utilities. */

#pragma segment UtilMain
void	PositionTwoRects(Rect outerRect, Rect *innerRect, Fixed horzRatio, Fixed vertRatio)
{
	short		outerRectHeight;
	short		outerRectWidth;
	short		innerRectHeight;
	short		innerRectWidth;
	short		yLocation;
	short		xLocation;

	outerRectHeight = outerRect.bottom - outerRect.top;
	outerRectWidth = outerRect.right - outerRect.left;

	innerRectHeight = (*innerRect).bottom - (*innerRect).top;
	innerRectWidth = (*innerRect).right - (*innerRect).left;
		yLocation = Fix2Long (FixMul (Long2Fix (outerRectHeight - innerRectHeight), vertRatio))
			+ outerRect.top;
		xLocation = Fix2Long (FixMul (Long2Fix (outerRectWidth - innerRectWidth), horzRatio))
			+ outerRect.left;

	(*innerRect).top = yLocation;
	(*innerRect).left = xLocation;
	(*innerRect).bottom = yLocation + innerRectHeight;
	(*innerRect).right = xLocation + innerRectWidth;
}

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

/* InitUtilities sets up some global variables for use by the utilities package.  If you call
   StandardInitialization, you don't need to call this, as it will do it for you. */
#pragma segment UtilInit

void	InitUtilities(void)
{
	Handle	apParam;
	Handle	bndlResource;

	gUtilitiesInited = false;

	/* Init all the Gestalt variables */
	gMachineType = GetGestaltResult (gestaltMachineType);
	gSystemVersion = GetGestaltResult (gestaltSystemVersion);
	gProcessorType = GetGestaltResult (gestaltProcessorType);

	/* We only concern ourselves with there being an FPU, not which type it is */
	gHasFPU = (GetGestaltResult (gestaltFPUType) != gestaltNoFPU);

	/*
	 *	We only concern ourselves with the major QD version number
	 *	0 for original QD, 1 for 8-bit color QD, and 2 for 32-bit QD
	 */
	gQDVersion = (GetGestaltResult (gestaltQuickdrawVersion) >> 8) & 0xFF;
	gKeyboardType = GetGestaltResult (gestaltKeyboardType);
	gAppleTalkVersion = GetGestaltResult (gestaltAppleTalkVersion);

	/* We only concern ourselves with there being an PMMU, not which type it is */
	gHasPMMU = GetGestaltResult (gestaltMMUType) >= gestalt68851;
	/* gAUXVersion = GetAUXVersion (); */

	gHasWaitNextEvent = TrapExists(_WaitNextEvent);
	gInBackground = false;

	GetAppParms(gAppName, &gAppResRef, &apParam);

	bndlResource = GetAppIndResource('BNDL', 1);
	if (bndlResource)
		gSignature = *(OSType *) (*bndlResource);

	gUtilitiesInited = true;
	
}

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

/*
 *	GetGestaltResult returns the result value from Gestalt for the specified selector.
 *	If Gestalt returned an error GetGestaltResult returns zero.  Use of this function
 *	is only cool if we don't care whether Gestalt returned an error.  In many cases
 *	you may need to know the exact Gestalt error code so then this routine would be
 *	inappropriate.  See GetAUXVersion for example.
 */
long	GetGestaltResult (OSType gestaltSelector)
{
	long	gestaltResult;

	if (Gestalt (gestaltSelector, &gestaltResult) == noErr)
		return (gestaltResult);
	else
		return (0);
}

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

/* GetAppIndResource gets a resource from the application's resource file by index */
#pragma segment UtilMain
Handle GetAppIndResource(ResType theType,short index)
{
	short	savedResFile;
	Handle	returnHandle;

	savedResFile = CurResFile ();
	UseResFile (gAppResRef);
	returnHandle = Get1IndResource(theType, index);
	UseResFile (savedResFile);
	return (returnHandle);
}	/* GetAppIndResource */

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

/* Check to see if a given trap is implemented. This is only used by the Initialize routine
   in this program, so we put it in the Initialize segment. */

#pragma segment UtilInit
Boolean TrapExists(short theTrap)
{
	TrapType	theTrapType;

	theTrapType = GetTrapType(theTrap);
	if ((theTrapType == ToolTrap) && ((theTrap &= 0x07FF) >= NumToolboxTraps()))
		theTrap = _Unimplemented;

	return (NGetTrapAddress(_Unimplemented, ToolTrap) != NGetTrapAddress(theTrap,
				  theTrapType));
}

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

/* InitGraf is always implemented (trap $A86E). If the trap table is big
   enough, trap $AA6E will always point to either Unimplemented or some other
   trap, but will never be the same as InitGraf. Thus, you can check the size
   of the trap table by asking if the address of trap $A86E is the same as
   $AA6E. */

#pragma segment UtilInit
short NumToolboxTraps(void)
{
	if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
		return (0x200);
	else
		return (0x400);
}

/*-----------------------------------------------------------------------------------------*/
/*	Check the bits of a trap number to determine its type. */

#pragma segment UtilInit
TrapType GetTrapType(short theTrap)
{
	/* OS traps start with A0, Tool with A8 or AA. */
	if ((theTrap & 0x0800) == 0)					/* per D.A. */
		return (OSTrap);
	else
		return (ToolTrap);
}

/*-----------------------------------------------------------------------------------------*/
/* GetAppResource gets a resource from the application's resource file by resource ID */
#pragma segment UtilMain
Handle GetAppResource(ResType theType,short theID)
{
	short	savedResFile;
	Handle	returnHandle;

	savedResFile = CurResFile ();
	UseResFile (gAppResRef);
	returnHandle = Get1Resource(theType, theID);
	UseResFile (savedResFile);
	return (returnHandle);
}	/* GetAppResource */

