1 line
55 KiB
C
Executable File
1 line
55 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
||
All rights reserved.
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
||
the limitations in the disclaimer below) provided that the following conditions are met:
|
||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
||
disclaimer in the documentation and/or other materials provided with the distribution.
|
||
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
||
derived from this software without specific prior written permission.
|
||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
||
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||
DAMAGE. */
|
||
|
||
#include "utl.h"
|
||
#define FILE_NUM 42
|
||
/*______________________________________________________________________
|
||
|
||
utl.c - Utilities.
|
||
|
||
Copyright © 1988, 1989, 1990 Northwestern University. Permission is granted
|
||
to use this code in your own projects, provided you give credit to both
|
||
John Norstad and Northwestern University in your about box or document.
|
||
|
||
This module exports miscellaneous reusable utility routines.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
|
||
|
||
#pragma segment utl
|
||
|
||
/*______________________________________________________________________
|
||
|
||
Global Variables.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
static SysEnvRec TheWorld; /* system environment record */
|
||
static Boolean GotSysEnviron = false;
|
||
/* true if sys environ has been
|
||
gotten */
|
||
|
||
|
||
static CursHandle *CursArray; /* ptr to array of cursor handles */
|
||
static short NumCurs; /* number of cursors to rotate */
|
||
static short TickInterval; /* number of ticks between rotations */
|
||
static short CurCurs; /* index of current cursor */
|
||
static short LastTick; /* tick count at loast rotation */
|
||
|
||
static ModalFilterProcPtr Filter; /* dialog filter proc */
|
||
static short CancelItem; /* item number of cancel button */
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_CenterDlogRect - Center a dialog rectangle.
|
||
|
||
Entry: rect = rectangle.
|
||
centerMain = true to center on main (menu bar) screen.
|
||
centerMain = false to center on the screen containing
|
||
the maximum intersection with the frontmost window.
|
||
|
||
Exit: rect = rectangle offset so that it is centered on
|
||
the specified screen, with twice as much space below
|
||
the rect as above.
|
||
|
||
See HIN 6.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_CenterDlogRect (Rect *rect, Boolean centerMain)
|
||
|
||
{
|
||
Rect screenRect; /* screen rectangle */
|
||
short mBHeight; /* menu bar height */
|
||
GDHandle gd; /* gdevice */
|
||
Rect windRect; /* window rectangle */
|
||
Boolean hasMB; /* true if screen contains menu bar */
|
||
|
||
mBHeight = utl_GetMBarHeight();
|
||
if (centerMain) {
|
||
screenRect = GetScreenBounds();
|
||
} else {
|
||
utl_GetWindGD(FrontWindow(), &gd, &screenRect, &windRect, &hasMB);
|
||
if (!hasMB) mBHeight = 0;
|
||
};
|
||
OffsetRect(rect,
|
||
(screenRect.right + screenRect.left - rect->right - rect->left) >> 1,
|
||
(screenRect.bottom + ((screenRect.top + mBHeight - rect->top)<<1) -
|
||
rect->bottom + 7) / 3);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_CenterRect - Center a rectangle on the main screen.
|
||
|
||
Entry: rect = rectangle.
|
||
|
||
Exit: rect = rectangle offset so that it is centered on
|
||
the main screen.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_CenterRect (Rect *rect)
|
||
|
||
{
|
||
Rect screenRect; /* main screen rectangle */
|
||
short mBHeight; /* menu bar height */
|
||
|
||
mBHeight = utl_GetMBarHeight();
|
||
screenRect = GetScreenBounds();
|
||
OffsetRect(rect,
|
||
(screenRect.right + screenRect.left - rect->right - rect->left) >> 1,
|
||
(screenRect.bottom - screenRect.top + mBHeight -
|
||
rect->bottom - rect->top) >> 1);
|
||
}
|
||
|
||
#ifdef NEVER
|
||
/*______________________________________________________________________
|
||
|
||
utl_CheckPack - Check to see if a package exists.
|
||
|
||
Entry: packNum = package number.
|
||
preload = true to preload package.
|
||
|
||
Exit: function result = true if package exists.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_CheckPack (short packNum, Boolean preload)
|
||
|
||
{
|
||
short trapNum; /* trap number */
|
||
Handle h; /* handle to PACK resource */
|
||
|
||
/* Check to make sure the trap exists, by comparing its trap address to
|
||
the trap address of the unimplemented trap. */
|
||
|
||
trapNum = packNum + 0x1e7;
|
||
if (NGetTrapAddress(trapNum & 0x3ff, ToolTrap) ==
|
||
NGetTrapAddress(_Unimplemented & 0x3ff, ToolTrap)) return false;
|
||
|
||
/* Check to make sure the package exists on the System file or in
|
||
ROM. If it's not in ROM make it nonpurgeable, if requested. */
|
||
|
||
if (preload) {
|
||
if (utl_Rom64()) {
|
||
h = GetResource_('PACK', packNum);
|
||
if (!h) return false;
|
||
HNoPurge_(h);
|
||
} else {
|
||
*(unsigned short*)RomMapInsert = 0xFF00;
|
||
h = GetResource_('PACK', packNum);
|
||
if (!h) return false;
|
||
if ((*(unsigned long*)h & 0x00FFFFFF) <
|
||
*(unsigned long*)ROMBase) {
|
||
h = GetResource_('PACK', packNum);
|
||
HNoPurge_(h);
|
||
};
|
||
};
|
||
return true;
|
||
} else {
|
||
SetResLoad(false);
|
||
if (!utl_Rom64()) *(unsigned short*)RomMapInsert = 0xFF00;
|
||
h = GetResource_('PACK', packNum);
|
||
SetResLoad(true);
|
||
if (h) return true; else return false;
|
||
};
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_CopyPString - Copy Pascal String.
|
||
|
||
Entry: dest = destination string.
|
||
source = source string.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_CopyPString (Str255 dest, Str255 source)
|
||
|
||
{
|
||
BMD(source,dest,*source+1);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_CouldDrag - Determine if a window could be dragged to a location.
|
||
|
||
Entry: windRect = window rectangle, in global coords.
|
||
offset = pixel offset used in DragRect calls.
|
||
|
||
Exit: function result = true if the window could have been
|
||
dragged to the specified position.
|
||
|
||
This routine is used when restoring windows to saved positions. According
|
||
to HIN 6, we must check to see if the window "could have been dragged to
|
||
the saved position."
|
||
|
||
The "offset" parameter is usually 4. When initializing the boundary rectangle
|
||
for DragWindow calls, normally the boundary rectangle of the desktop gray
|
||
region is inset by 4 pixels. If some value other than 4 is used, it should
|
||
be passed to CouldDrag as the "offset" parameter.
|
||
|
||
The algorithm used is the following: The routine computes the four squares
|
||
at the corners of the title bar. "true" is returned if and only if at least one
|
||
of these four squares is completely contained within the desktop gray region.
|
||
|
||
Three pixels are added to the offset to err on the side of requiring a larger
|
||
portion of the drag bar to be visible.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_CouldDrag (WindowPtr theWindow,Rect *windRect, short offset, short titleBarHeight, short leftRimWidth)
|
||
|
||
{
|
||
RgnHandle rgn=nil; /* scratch region handle */
|
||
Boolean could; /* function result */
|
||
short corner; /* which corner */
|
||
Rect r; /* corner rectangle */
|
||
RgnHandle grayRgn;
|
||
|
||
rgn = NewRgn();
|
||
grayRgn = NewRgn();
|
||
if (grayRgn)
|
||
{
|
||
CopyRgn(GetGrayRgn(),grayRgn);
|
||
DockedWinRemove(grayRgn,theWindow);
|
||
}
|
||
{
|
||
could = false;
|
||
offset += 3;
|
||
for (corner = 1; corner <= 4; corner++) {
|
||
switch (corner) {
|
||
case 1:
|
||
r.top = windRect->top - titleBarHeight;
|
||
r.left = windRect->left;
|
||
break;
|
||
case 2:
|
||
r.top = windRect->top - offset;
|
||
r.left = windRect->left;
|
||
break;
|
||
case 3:
|
||
r.top = windRect->top - titleBarHeight;
|
||
r.left = windRect->right - offset;
|
||
break;
|
||
case 4:
|
||
r.top = windRect->top - offset;
|
||
r.left = windRect->right - offset;
|
||
break;
|
||
};
|
||
r.bottom = r.top + offset;
|
||
r.right = r.left + offset;
|
||
RectRgn(rgn, &r);
|
||
DiffRgn(rgn, grayRgn, rgn);
|
||
if (EmptyRgn(rgn)) {
|
||
could = true;
|
||
break;
|
||
};
|
||
};
|
||
}
|
||
if (rgn) DisposeRgn(rgn);
|
||
if (grayRgn) DisposeRgn(grayRgn);
|
||
return could;
|
||
}
|
||
|
||
#ifdef NEVER
|
||
/*______________________________________________________________________
|
||
|
||
utl_FixStdFile - Fix Standard File Pacakge.
|
||
|
||
This routine should be called before calling the Standard File
|
||
package if there's any chance that SFSaveDisk might specify
|
||
a volume that has been umounted. Standard File gets confused if this
|
||
happens and presents an alert telling the user that a "system error"
|
||
has occurred.
|
||
|
||
This routine checks to make sure that SFSaveDisk specifies a volume
|
||
that is still mounted. If not, it sets it to the first mounted
|
||
volume, and it sets CurDirStore to the root directory on that volume.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_FixStdFile (void)
|
||
|
||
{
|
||
ParamBlockRec vBlock; /* vol info param block */
|
||
|
||
vBlock.volumeParam.ioNamePtr = nil;
|
||
vBlock.volumeParam.ioVRefNum = -*(short*)SFSaveDisk;
|
||
vBlock.volumeParam.ioVolIndex = 0;
|
||
if (PBGetVInfo(&vBlock, false)) {
|
||
vBlock.volumeParam.ioVolIndex = 1;
|
||
(void) PBGetVInfo(&vBlock, false);
|
||
*(short*)SFSaveDisk = -vBlock.volumeParam.ioVRefNum;
|
||
if (*(short*)FSFCBLen > 0) *(long*)CurDirStore = fsRtDirID;
|
||
};
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_FlashButton - Flash Dialog Button.
|
||
|
||
Entry: theDialog = pointer to dialog.
|
||
itemNo = item number of button to flash.
|
||
|
||
The push button is inverted for 8 ticks. See HIN #10.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_FlashButton (DialogPtr theDialog, short itemNo)
|
||
|
||
{
|
||
short itemType; /* item type */
|
||
Handle item; /* item handle */
|
||
Rect box; /* item rectangle */
|
||
short roundFactor; /* rounded corner factor for InvertRoundRect */
|
||
long tickEnd; /* tick count to end flash */
|
||
|
||
GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
|
||
SetPort(GetDialogPort(theDialog));
|
||
roundFactor = (box.bottom - box.top)>>1;
|
||
InvertRoundRect(&box, roundFactor, roundFactor);
|
||
tickEnd = TickCount() + 8;
|
||
while (TickCount() < tickEnd);
|
||
InvertRoundRect(&box, roundFactor, roundFactor);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_FrameItem
|
||
|
||
Entry: theWindow = pointer to dialog window.
|
||
itemNo = dialog item number.
|
||
|
||
Exit: dialog item rectangle framed.
|
||
|
||
This function is for use as a Dialog Manager user item procedure.
|
||
It is particularly useful for drawing rules (straight lines). Simply
|
||
define the user item rectangle with bottom=top+1 or right=left+1.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
pascal void utl_FrameItem (DialogPtr theDialog, short itemNo)
|
||
|
||
{
|
||
short itemType; /* item type */
|
||
Handle item; /* item handle */
|
||
Rect box; /* item rectangle */
|
||
|
||
GetDialogItem(theDialog, itemNo, &itemType, &item, &box);
|
||
FrameRect(&box);
|
||
}
|
||
|
||
#ifdef NEVER
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetApplVol - Get the volume reference number of the application volume.
|
||
|
||
Exit: function result = volume reference number of the volume
|
||
containing the current application.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
short utl_GetApplVol (void)
|
||
|
||
{
|
||
short vRefNum; /* vol ref num */
|
||
|
||
GetVRefNum(*(short*)(CurMap), &vRefNum);
|
||
return vRefNum;
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetFontNumber - Get Font Number.
|
||
|
||
Entry: fontName = font name.
|
||
|
||
Exit: function result = true if font exists.
|
||
fontNum = font number.
|
||
|
||
Copied from TN 191.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_GetFontNumber (Str255 fontName, short *fontNum)
|
||
|
||
{
|
||
Str255 systemFontName;
|
||
|
||
GetFNum(fontName, fontNum);
|
||
if (*fontNum) {
|
||
return true;
|
||
} else {
|
||
GetFontName(0, systemFontName);
|
||
return StringSame(fontName, systemFontName);
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetMBarHeight - Get Menu Bar Height
|
||
|
||
Exit: function result = menu bar height.
|
||
|
||
See TN 117.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
short utl_GetMBarHeight (void)
|
||
|
||
{
|
||
static short mBHeight = 0;
|
||
|
||
if (!mBHeight) {
|
||
mBHeight = utl_Rom64() ? 20 : GetMBarHeight();
|
||
};
|
||
return mBHeight;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetNewControl_ - Get New Control.
|
||
|
||
Entry: controlID = resource id of CNTL resource.
|
||
theWindow = pointer to window record.
|
||
|
||
Exit: function result = handle to new control record.
|
||
|
||
This routine is identical to the Control Manager routine GetNewControl_,
|
||
except it does not release or make purgeable the CNTL resource.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
ControlHandle utl_GetNewControl (short controlID,
|
||
WindowPtr theWindow)
|
||
|
||
{
|
||
Rect boundsRect; /* boundary rectangle */
|
||
short value; /* initial control value */
|
||
Boolean visible; /* true if visible */
|
||
short max; /* max control value */
|
||
short min; /* min control value */
|
||
short procID; /* window proc id */
|
||
long refCon; /* refCon field for window record */
|
||
Str255 title; /* window title */
|
||
Handle theRez; /* handle to CNTL resource */
|
||
|
||
theRez = GetResource_('CNTL', controlID);
|
||
boundsRect = *(Rect*)(*theRez);
|
||
value = *(short*)(*theRez+8);
|
||
visible = *(Boolean*)(*theRez+10);
|
||
max = *(short*)(*theRez+12);
|
||
min = *(short*)(*theRez+14);
|
||
procID = *(short*)(*theRez+16);
|
||
refCon = *(long*)(*theRez+18);
|
||
utl_CopyPString(title, *theRez+22);
|
||
return NewControl(theWindow, &boundsRect, title, visible, value,
|
||
min, max, procID, refCon);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetNewDialog - Get New Dialog.
|
||
|
||
Entry: dialogID = resource id of DLOG resource.
|
||
dStorage = pointer to dialog record.
|
||
behind = window to insert in back of.
|
||
|
||
Exit: function result = pointer to new dialog record.
|
||
|
||
This routine is identical to the Dialog Manager routine GetNewDialog,
|
||
except it does not release or make purgeable the DLOG resource.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
DialogPtr utl_GetNewDialog (short dialogID, Ptr dStorage,
|
||
WindowPtr behind)
|
||
|
||
{
|
||
Rect boundsRect; /* boundary rectangle */
|
||
short procID; /* window proc id */
|
||
Boolean visible; /* true if visible */
|
||
Boolean goAwayFlag; /* true if window has go away box */
|
||
long refCon; /* refCon field for window record */
|
||
Str255 title; /* window title */
|
||
Handle theRez; /* handle to DLOG resource */
|
||
short itemID; /* rsrc id of item list */
|
||
Handle items; /* handle to item list */
|
||
|
||
theRez = GetResource_('DLOG', dialogID);
|
||
boundsRect = *(Rect*)(*theRez);
|
||
procID = *(short*)(*theRez+8);
|
||
visible = *(Boolean*)(*theRez+10);
|
||
goAwayFlag = *(Boolean*)(*theRez+12);
|
||
refCon = *(long*)(*theRez+14);
|
||
itemID = *(short*)(*theRez+18);
|
||
utl_CopyPString(title, *theRez+20);
|
||
items = GetResource_('DITL', itemID);
|
||
return NewDialog(dStorage, &boundsRect, title, visible, procID, behind,
|
||
goAwayFlag, refCon, items);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetNewWindow - Get New Window.
|
||
|
||
Entry: windowID = resource id of WIND resource.
|
||
wStorage = pointer to window record.
|
||
behind = window to insert in back of.
|
||
|
||
Exit: function result = pointer to new window record.
|
||
|
||
This routine is identical to the Window Manager routine GetNewWindow,
|
||
except it does not release or make purgeable the WIND resource.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
WindowPtr utl_GetNewWindow (short windowID, Ptr wStorage,
|
||
WindowPtr behind)
|
||
|
||
{
|
||
Rect boundsRect; /* boundary rectangle */
|
||
short procID; /* window proc id */
|
||
Boolean visible; /* true if visible */
|
||
Boolean goAwayFlag; /* true if window has go away box */
|
||
long refCon; /* refCon field for window record */
|
||
Str255 title; /* window title */
|
||
Handle theRez; /* handle to WIND resource */
|
||
|
||
theRez = GetResource_('WIND', windowID);
|
||
boundsRect = *(Rect*)(*theRez);
|
||
procID = *(short*)(*theRez+8);
|
||
visible = *(Boolean*)(*theRez+10);
|
||
goAwayFlag = *(Boolean*)(*theRez+12);
|
||
refCon = *(long*)(*theRez+14);
|
||
utl_CopyPString(title, *theRez+18);
|
||
return NewWindow(wStorage, &boundsRect, title, visible, procID, behind,
|
||
goAwayFlag, refCon);
|
||
}
|
||
|
||
#ifdef NEVER
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetSysVol - Get the volume reference number of the system volume.
|
||
|
||
Exit: function result = volume reference number of the volume
|
||
containing the currently active system file.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
short utl_GetSysVol (void)
|
||
|
||
{
|
||
|
||
short vRefNum; /* vol ref num */
|
||
|
||
GetVRefNum(*(short*)(SysMap), &vRefNum);
|
||
return vRefNum;
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetWindGD - Get the GDevice containing a window.
|
||
|
||
Entry: theWindow = pointer to window.
|
||
|
||
Exit: gd = handle to GDevice, or nil if no color QD.
|
||
screenRect = bounding rectangle of GDevice, or
|
||
qd.screenBits.bounds if no color QD.
|
||
windRect = content rectangle of window, in global
|
||
coords.
|
||
hasMB = true if this screen contains the menu bar.
|
||
|
||
The routine determines the GDevice (screen) containing the maximum
|
||
intersection with a window. See TN 79.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_GetWindGD (WindowPtr theWindow, GDHandle *gd,
|
||
Rect *screenRect, Rect *windRect, Boolean *hasMB)
|
||
|
||
{
|
||
GrafPtr savePort; /* saved grafport */
|
||
|
||
GetPortBounds(GetWindowPort(theWindow),windRect);
|
||
GetPort(&savePort);
|
||
SetPort(GetWindowPort(theWindow));
|
||
LocalToGlobal((Point*)&windRect->top);
|
||
LocalToGlobal((Point*)&windRect->bottom);
|
||
utl_GetRectGDStuff(gd,screenRect,windRect,TitleBarHeight(theWindow),LeftRimWidth(theWindow),hasMB);
|
||
SetPort_(savePort);
|
||
}
|
||
|
||
void utl_GetRectGDStuff (GDHandle *gd,
|
||
Rect *screenRect, Rect *windRect, short titleBarHeight, short leftRimWidth,Boolean *hasMB)
|
||
|
||
{
|
||
Rect sectRect; /* intersection rect */
|
||
GDHandle curDevice; /* current GDevice */
|
||
GDHandle dominantDevice; /* dominant GDevice */
|
||
long sectArea; /* intersection area */
|
||
long maxArea; /* max intersection area */
|
||
|
||
if (utl_HaveColor()) {
|
||
windRect->top -= titleBarHeight;
|
||
windRect->left -= leftRimWidth;
|
||
curDevice = GetDeviceList();
|
||
maxArea = 0;
|
||
dominantDevice = nil;
|
||
while (curDevice) {
|
||
if (TestDeviceAttribute(curDevice, screenDevice) &&
|
||
TestDeviceAttribute(curDevice, screenActive)) {
|
||
SectRect(windRect, &(**curDevice).gdRect, §Rect);
|
||
sectArea = (long)(sectRect.right - sectRect.left) *
|
||
(long)(sectRect.bottom - sectRect.top);
|
||
if (sectArea > maxArea) {
|
||
maxArea = sectArea;
|
||
dominantDevice = curDevice;
|
||
};
|
||
};
|
||
curDevice = GetNextDevice(curDevice);
|
||
};
|
||
windRect->top += titleBarHeight;
|
||
windRect->left += leftRimWidth;
|
||
if (dominantDevice) {
|
||
*gd = dominantDevice;
|
||
*screenRect = (**dominantDevice).gdRect;
|
||
*hasMB = dominantDevice == GetMainDevice();
|
||
} else {
|
||
*gd = nil;
|
||
*screenRect = GetScreenBounds();
|
||
*hasMB = true;
|
||
};
|
||
} else {
|
||
*gd = nil;
|
||
*screenRect = GetScreenBounds();
|
||
*hasMB = true;
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetRectGD - Get the GDevice containing a rect.
|
||
|
||
Entry: windRect - pointer to the rectangle
|
||
|
||
Exit: gd = handle to GDevice, or nil if no color QD.
|
||
|
||
The routine determines the GDevice (screen) containing the maximum
|
||
intersection with a rect. See TN 79.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_GetRectGD (Rect *windRect, GDHandle *gd)
|
||
|
||
{
|
||
Rect sectRect; /* intersection rect */
|
||
GDHandle curDevice; /* current GDevice */
|
||
GDHandle dominantDevice; /* dominant GDevice */
|
||
long sectArea; /* intersection area */
|
||
long maxArea; /* max intersection area */
|
||
|
||
if (utl_HaveColor()) {
|
||
curDevice = GetDeviceList();
|
||
maxArea = 0;
|
||
dominantDevice = nil;
|
||
while (curDevice) {
|
||
if (TestDeviceAttribute(curDevice, screenDevice) &&
|
||
TestDeviceAttribute(curDevice, screenActive)) {
|
||
SectRect(windRect, &(**curDevice).gdRect, §Rect);
|
||
sectArea = (long)(sectRect.right - sectRect.left) *
|
||
(long)(sectRect.bottom - sectRect.top);
|
||
if (sectArea > maxArea) {
|
||
maxArea = sectArea;
|
||
dominantDevice = curDevice;
|
||
};
|
||
};
|
||
curDevice = GetNextDevice(curDevice);
|
||
};
|
||
if (dominantDevice) {
|
||
*gd = dominantDevice;
|
||
} else {
|
||
*gd = nil;
|
||
};
|
||
} else {
|
||
*gd = nil;
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetIndGD - Get the nth GDevice.
|
||
|
||
Entry: n = device index.
|
||
|
||
Exit: gd = handle to GDevice, or nil if no color QD.
|
||
screenRect = bounding rectangle of GDevice, or
|
||
qd.screenBits.bounds if no color QD.
|
||
hasMB = true if this screen contains the menu bar.
|
||
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_GetIndGD (short n,GDHandle *gd, Rect *screenRect, Boolean *hasMB)
|
||
|
||
{
|
||
GDHandle curDevice; /* current GDevice */
|
||
GDHandle dominantDevice; /* dominant GDevice */
|
||
|
||
if (utl_HaveColor()) {
|
||
dominantDevice = nil;
|
||
curDevice = GetDeviceList();
|
||
while (curDevice && n--) {
|
||
if (TestDeviceAttribute(curDevice, screenDevice) &&
|
||
TestDeviceAttribute(curDevice, screenActive))
|
||
dominantDevice = curDevice;
|
||
curDevice = GetNextDevice(curDevice);
|
||
}
|
||
if (dominantDevice) {
|
||
if (gd) *gd = dominantDevice;
|
||
if (screenRect) *screenRect = (**dominantDevice).gdRect;
|
||
if (hasMB) *hasMB = dominantDevice == GetMainDevice();
|
||
} else {
|
||
if (gd) *gd = nil;
|
||
if (screenRect) *screenRect = GetScreenBounds();
|
||
if (hasMB) *hasMB = true;
|
||
};
|
||
} else {
|
||
if (gd) *gd = nil;
|
||
if (screenRect) *screenRect = GetScreenBounds();
|
||
if (hasMB) *hasMB = true;
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_GetVolFilCnt - Get the number of files on a volume.
|
||
|
||
Entry: volRefNum = volume reference number of volume.
|
||
|
||
Exit: function result = number of files on volume.
|
||
|
||
For serdver volumes this function always returns 0.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
long utl_GetVolFilCnt (short volRefNum)
|
||
|
||
{
|
||
HParamBlockRec pBlock; /* param block for PHBGetVInfo */
|
||
|
||
pBlock.volumeParam.ioNamePtr = nil;
|
||
pBlock.volumeParam.ioVRefNum = volRefNum;
|
||
pBlock.volumeParam.ioVolIndex = 0;
|
||
(void) PBHGetVInfo(&pBlock, false);
|
||
return pBlock.volumeParam.ioVFilCnt;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_HaveColor - Determine if system has color QuickDraw.
|
||
|
||
Exit: function result = true if we have color QD.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_HaveColor (void)
|
||
|
||
{
|
||
#if 0
|
||
SInt32 gestaltResult;
|
||
|
||
if (!Gestalt(gestaltQuickdrawFeatures, &gestaltResult))
|
||
return (gestaltResult & gestaltHasColor) != 0;
|
||
return false; // shouldn't happen
|
||
#endif
|
||
return true;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_InitSpinCursor - Initialize animated cursor.
|
||
|
||
Entry: cursArray = array of handles to cursors.
|
||
numCurs = number of cursors to rotate.
|
||
tickInterval = interval between cursor rotations.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_InitSpinCursor (CursHandle *cursArray, short numCurs,
|
||
short tickInterval)
|
||
|
||
{
|
||
CursHandle h;
|
||
|
||
CursArray = cursArray;
|
||
CurCurs = 0;
|
||
NumCurs = numCurs;
|
||
TickInterval = tickInterval;
|
||
LastTick = TickCount();
|
||
h = *cursArray;
|
||
SetCursor(*h);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_InvalGrow - Invalidate Grow Icon.
|
||
|
||
Entry: theWindow = pointer to window.
|
||
|
||
This routine should be called before and after calling SizeWindow
|
||
for windows with grow icons.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_InvalGrow (WindowPtr theWindow)
|
||
|
||
{
|
||
Rect r; /* rect to be invalidated */
|
||
|
||
GetPortBounds(GetWindowPort(theWindow),&r);
|
||
r.top = r.bottom - 15;
|
||
r.left = r.right - 15;
|
||
InvalWindowRect(theWindow,&r);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_IsDAWindow - Check to see if a window is a DA.
|
||
|
||
Entry: theWindow = pointer to dialog window.
|
||
|
||
|
||
Exit: function result = true if DA window.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_IsDAWindow (WindowPtr theWindow)
|
||
|
||
{
|
||
return GetWindowKind(theWindow) < 0;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_IsLaser - Check Printer for LaserWriter.
|
||
|
||
Entry: hPrint = handle to print record.
|
||
|
||
Exit: function result = true if LaserWriter.
|
||
|
||
_____________________________________________________________________*/
|
||
|
||
#if 0
|
||
Boolean utl_IsLaser (THPrint hPrint)
|
||
|
||
{
|
||
unsigned char wDev; /* printer device */
|
||
|
||
wDev = (**hPrint).prStl.wDev >> 8;
|
||
return wDev==3 || wDev==4;
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_PlugParams - Plug parameters into message.
|
||
|
||
Entry: line1 = input line.
|
||
p0, p1, p2, p3 = parameters.
|
||
|
||
Exit: line2 = output line.
|
||
|
||
This routine works just like the toolbox routine ParamText.
|
||
The input line may contain place-holders ^0, ^1, ^2, and ^3,
|
||
which are replaced by the parameters p0-p3. The input line
|
||
must not contain any other ^ characters. The input and output lines
|
||
may not be the same string. Pass nil for parameters which don't
|
||
occur in line1. If the output line exceeds 255 characters it's
|
||
truncated.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_PlugParams (Str255 line1, Str255 line2, Str255 p0,
|
||
Str255 p1, Str255 p2, Str255 p3)
|
||
|
||
{
|
||
/* MJN *//* changed type declaration for in, out, inEnd, outEnd, and param from char* to unsigned char*,
|
||
so that this routine will work properly with strings over 127 characters in length */
|
||
unsigned char *in; /* pointer to cur pos in input line */
|
||
unsigned char *out; /* pointer to cur pos in output line */
|
||
unsigned char *inEnd; /* pointer to end of input line */
|
||
unsigned char *outEnd; /* pointer to end of output line */
|
||
unsigned char *param; /* pointer to param to be plugged */
|
||
short len; /* length of param */
|
||
|
||
in = line1+1;
|
||
out = line2+1;
|
||
inEnd = line1 + 1 + *line1;
|
||
outEnd = line2 + 256;
|
||
while (in < inEnd ) {
|
||
if (*in == '^') {
|
||
in++;
|
||
if (in >= inEnd) break;
|
||
switch (*in++) {
|
||
case '0':
|
||
param = p0;
|
||
break;
|
||
case '1':
|
||
param = p1;
|
||
break;
|
||
case '2':
|
||
param = p2;
|
||
break;
|
||
case '3':
|
||
param = p3;
|
||
break;
|
||
default:
|
||
continue;
|
||
};
|
||
if (!param) continue;
|
||
len = *param;
|
||
if (out + len > outEnd) len = outEnd - out;
|
||
BMD(param+1,out,len);
|
||
out += len;
|
||
} else {
|
||
if (out >= outEnd) break;
|
||
*out++ = *in++;
|
||
};
|
||
};
|
||
*line2 = out - (line2+1);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_RestoreWindowPos - Restore Window Position.
|
||
|
||
Entry: theWindow = pointer to window.
|
||
userState = saved user state rectangle for the window.
|
||
zoomed = true if window in zoomed state when saved.
|
||
offset = pixel offset used in DragRect calls.
|
||
computeStdState = pointer to function to compute standard state.
|
||
computeDefState = pointer to function to compute default state.
|
||
|
||
Exit: window position, size, and zoom state restored.
|
||
userState = new user state.
|
||
|
||
See HIN 6: "When reopening a movable window, check its saved
|
||
position. If the window is in a position to which the user could
|
||
have dragged it, then leave it there. If the window can be zoomed
|
||
and was in the zoomed state when it was last closed, put it in the
|
||
zoomed state again. (Note that the current and previous zoomed states
|
||
are not necessarily the same, since the window may be reopened on a
|
||
different monitor.) If the window is not in a position to which the
|
||
user could have dragged it, then it must be relocated, so use the
|
||
default location. However, do not automatically use the default size
|
||
when using the default location; if the entire window would be visible
|
||
using the default location and stored size, then use the stored size."
|
||
|
||
The "offset" parameter is usually 4. When initializing the boundary rectangle
|
||
for DragWindow calls, normally the boundary rectangle of the desktop gray
|
||
region is inset by 4 pixels. If some value other than 4 is used, it should
|
||
be passed to RestoreWindowPos as the "offset" parameter.
|
||
|
||
The computeStdState function is passed a pointer to the window. Given
|
||
the userState in the window zoom info, it must compute the standard
|
||
(zoom) state in the window zoom info. This is an application-dependent
|
||
function.
|
||
|
||
The computeDefState function must determine the default position and
|
||
size of a new window, and return the result as a rectangle. This may
|
||
involve invocation of a staggering algorithm or some other algorithm.
|
||
This is an application-dependent function.
|
||
|
||
Changed to keep window smaller than the desktop's bounding box.
|
||
(s-dorner@uiuc.edu, 12/16/91)
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_RestoreWindowPos (WindowPtr theWindow, Rect *userState,
|
||
Boolean zoomed, short offset, short titleBarHeight, short leftRimWidth,
|
||
utl_ComputeStdStatePtr computeStdState,
|
||
utl_ComputeDefStatePtr computeDefState)
|
||
|
||
{
|
||
MyWindowPtr win; /* pointer to one of our own window structures */
|
||
WindowPtr winWP;
|
||
short userHeight; /* height of userState */
|
||
short userWidth; /* width of userState */
|
||
Rect r; /* scratch rectangle */
|
||
RgnHandle rgn; /* scratch region */
|
||
Rect stdState; /* standard state */
|
||
short windHeight; /* window height */
|
||
short windWidth; /* window width */
|
||
|
||
win = GetWindowMyWindowPtr (theWindow);
|
||
if (!win)
|
||
return;
|
||
|
||
winWP = GetMyWindowWindowPtr(win);
|
||
SanitizeSize(win,userState);
|
||
if (titleBarHeight>0 && !utl_CouldDrag(theWindow,userState, offset,titleBarHeight,leftRimWidth)) {
|
||
userHeight = userState->bottom - userState->top;
|
||
userWidth = userState->right - userState->left;
|
||
(*computeDefState)(theWindow, userState);
|
||
if (!zoomed) {
|
||
r = *userState;
|
||
r.bottom = r.top + userHeight;
|
||
r.right = r.left + userWidth;
|
||
r.top -= titleBarHeight;
|
||
r.left -= leftRimWidth;
|
||
InsetRect(&r, -1, -1);
|
||
rgn = NewRgn();
|
||
RectRgn(rgn, &r);
|
||
DiffRgn(rgn, GetGrayRgn(), rgn);
|
||
if (EmptyRgn(rgn)) {
|
||
userState->bottom = userState->top + userHeight;
|
||
userState->right = userState->left + userWidth;
|
||
};
|
||
DisposeRgn(rgn);
|
||
};
|
||
};
|
||
MoveWindow(theWindow, userState->left, userState->top, false);
|
||
windHeight = userState->bottom - userState->top;
|
||
windWidth = userState->right - userState->left;
|
||
if (!win->isRunt) SizeWindow(theWindow, windWidth, windHeight, true);
|
||
SetWindowUserState(winWP,userState);
|
||
(*computeStdState)(theWindow);
|
||
if (zoomed) {
|
||
GetWindowStandardState(winWP,&stdState);
|
||
MoveWindow(theWindow, stdState.left, stdState.top, false);
|
||
windHeight = stdState.bottom - stdState.top;
|
||
windWidth = stdState.right - stdState.left;
|
||
if (!win->isRunt) SizeWindow(theWindow, windWidth, windHeight, true);
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_Rom64 - Check to see if we have the old 64K ROM.
|
||
|
||
Exit: function result = true if 64K ROM.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_Rom64 (void)
|
||
|
||
{
|
||
return(False);
|
||
#ifdef NEVER
|
||
return *(short*)ROM85 < 0;
|
||
#endif
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_RFSanity - Check a Resource File's Sanity.
|
||
|
||
Entry: *fName = file name.
|
||
|
||
Exit: *sane = true if resource fork is sane.
|
||
function result = error code.
|
||
|
||
This routine checks the sanity of a resource file. The Resource Manager
|
||
does not do error checking, and can bomb or hang if you use it to open
|
||
a damaged resource file. This routine can be called first to precheck
|
||
the file.
|
||
|
||
The routine checks the entire resource map.
|
||
|
||
It is the caller's responsibility to set the proper default volume and
|
||
directory.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
OSErr utl_RFSanity (FSSpecPtr spec, Boolean *sane)
|
||
|
||
{
|
||
short refNum; /* file refnum */
|
||
long count; /* number of bytes to read */
|
||
long logEOF; /* logical EOF */
|
||
Ptr map; /* pointer to resource map */
|
||
unsigned long dataLWA; /* offset in file of data end */
|
||
unsigned long mapLWA; /* offset in file of map end */
|
||
unsigned short typeFWA; /* offset from map begin to type list */
|
||
unsigned short nameFWA; /* offset from map begin to name list */
|
||
unsigned char *pType; /* pointer into type list */
|
||
unsigned char *psName; /* pointer to start of name list */
|
||
unsigned char *pMapEnd; /* pointer to end of map */
|
||
short nType; /* number of resource types in map */
|
||
unsigned char *pTypeEnd; /* pointer to end of type list */
|
||
short nRes; /* number of resources of given type */
|
||
unsigned short refFWA; /* offset from type list to ref list */
|
||
unsigned char *pRef; /* pointer into reference list */
|
||
unsigned char *pRefEnd; /* pointer to end of reference list */
|
||
unsigned short resNameFWA; /* offset from name list to resource name */
|
||
unsigned char *pResName; /* pointer to resource name */
|
||
unsigned long resDataFWA; /* offset from data begin to resource data */
|
||
Boolean mapOK; /* true if map is sane */
|
||
OSErr rCode; /* error code */
|
||
|
||
struct {
|
||
unsigned long dataFWA; /* offset in file of data */
|
||
unsigned long mapFWA; /* offset in file of map */
|
||
unsigned long dataLen; /* data area length */
|
||
unsigned long mapLen; /* map area length */
|
||
} header;
|
||
|
||
/* Open the resource file. */
|
||
if (rCode = FSpOpenRF(spec,fsRdPerm,&refNum)) {
|
||
if (rCode == fnfErr || rCode == permErr) {
|
||
*sane = true;
|
||
return noErr;
|
||
} else {
|
||
return rCode;
|
||
};
|
||
};
|
||
|
||
/* Get the logical eof of the file. */
|
||
|
||
if (rCode = GetEOF(refNum, &logEOF)) return rCode;
|
||
if (!logEOF) {
|
||
*sane = true;
|
||
if (rCode = MyFSClose(refNum)) return rCode;
|
||
return noErr;
|
||
};
|
||
|
||
/* Read and validate the resource header. */
|
||
|
||
count = 16;
|
||
if (rCode = ARead(refNum, &count, (Ptr)&header)) {
|
||
MyFSClose(refNum);
|
||
return rCode;
|
||
};
|
||
dataLWA = header.dataFWA + header.dataLen;
|
||
mapLWA = header.mapFWA + header.mapLen;
|
||
mapOK = count == 16;
|
||
mapOK = mapOK && header.mapLen > 28;
|
||
mapOK = mapOK && header.dataFWA < 0x01000000;
|
||
mapOK = mapOK && header.mapFWA < 0x01000000;
|
||
mapOK = mapOK && dataLWA <= logEOF;
|
||
mapOK = mapOK && mapLWA <= logEOF;
|
||
mapOK = mapOK && (dataLWA <= header.mapFWA || mapLWA <= header.dataFWA);
|
||
|
||
/* Read the resource map. */
|
||
|
||
map = nil;
|
||
if (mapOK) {
|
||
map = NuPtr(header.mapLen);
|
||
if (!map) rCode = MemError();
|
||
else if (!(rCode = SetFPos(refNum, fsFromStart, header.mapFWA))) {
|
||
count = header.mapLen;
|
||
rCode = ARead(refNum, &count, map);
|
||
};
|
||
};
|
||
|
||
/* Verify the type list and name list offsets. */
|
||
|
||
if (mapOK && !rCode) {
|
||
typeFWA = *(unsigned short*)(map+24);
|
||
nameFWA = *(unsigned short*)(map+26);
|
||
mapOK = typeFWA == 28 && nameFWA >= typeFWA && nameFWA <= header.mapLen &&
|
||
!(typeFWA & 1) && !(nameFWA & 1);
|
||
};
|
||
|
||
/* Verify the type list, reference lists, and name list. */
|
||
|
||
if (mapOK && !rCode) {
|
||
pType = map + typeFWA;
|
||
psName = map + nameFWA;
|
||
pMapEnd = map + header.mapLen;
|
||
nType = *(short*)pType + 1;
|
||
pType += 2;
|
||
pTypeEnd = pType + (nType<<3);
|
||
if (mapOK = pTypeEnd <= pMapEnd) {
|
||
while (pType < pTypeEnd) {
|
||
nRes = *(short*)(pType+4) + 1;
|
||
refFWA = *(unsigned short*)(pType+6);
|
||
pRef = map + typeFWA + refFWA;
|
||
pRefEnd = pRef + 12*nRes;
|
||
if (!(mapOK = pRef >= pTypeEnd && pRef < psName &&
|
||
!(refFWA & 1))) break;
|
||
while (pRef < pRefEnd) {
|
||
resNameFWA = *(unsigned short*)(pRef+2);
|
||
if (resNameFWA != 0xFFFF) {
|
||
pResName = psName + resNameFWA;
|
||
if (!(mapOK = pResName + *pResName < pMapEnd)) break;
|
||
};
|
||
resDataFWA = *(unsigned long*)(pRef+4) & 0x00FFFFFF;
|
||
if (!(mapOK = header.dataFWA + resDataFWA < dataLWA)) break;
|
||
pRef += 12;
|
||
};
|
||
if (!mapOK) break;
|
||
pType += 8;
|
||
};
|
||
};
|
||
};
|
||
|
||
/* Dispose of the resource map, close the file and return. */
|
||
|
||
if (map) ZapPtr(map);
|
||
if (!rCode) {
|
||
rCode = MyFSClose(refNum);
|
||
} else {
|
||
(void) MyFSClose(refNum);
|
||
};
|
||
*sane = mapOK;
|
||
return rCode;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_SaveWindowPos - Save Window Position.
|
||
|
||
Entry: theWindow = window pointer.
|
||
|
||
Exit: userState = user state rectangle of the window.
|
||
zoomed = true if window zoomed.
|
||
|
||
See HIN 6: "Before closing a movable window, check to see if its
|
||
location or size have changed. If so, save the new location and
|
||
size. If the window can be zoomed, save the user state and also
|
||
save whether or not the window is in the zoomed (standard) sate."
|
||
|
||
We assume in this routine that the caller has already kept track
|
||
of the fact that this window's location or size has changed, and that
|
||
we do indeed need to save the location and size.
|
||
|
||
This routine only works if the window's origin has not been offset.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_SaveWindowPos (WindowPtr theWindow, Rect *userState, Boolean *zoomed)
|
||
|
||
{
|
||
GrafPtr savedPort; /* saved grafport */
|
||
Rect curState; /* current window rect, global coords */
|
||
Rect stdState; /* standard (zoom) rect, global coords */
|
||
Point p; /* scratch point */
|
||
Rect r; /* scratch rect */
|
||
|
||
GetPort(&savedPort);
|
||
SetPort_(GetWindowPort(theWindow));
|
||
SetPt(&p, 0, 0);
|
||
LocalToGlobal(&p);
|
||
GetPortBounds(GetWindowPort(theWindow),&curState);
|
||
OffsetRect(&curState, p.h, p.v);
|
||
if (IsKnownWindowMyWindow(theWindow))
|
||
{
|
||
MyWindowPtr win = GetWindowMyWindowPtr(theWindow);
|
||
if (!RectHi(curState) || RectHi(curState)<win->minSize.v)
|
||
curState.bottom = curState.top + MAX(win->minSize.v,RectHi(win->contR));
|
||
}
|
||
|
||
/* Determine if window is zoomed. The criteria is that both the
|
||
top left and bottom right corners of the current window rectangle
|
||
and the standard (zoom) rectangle must be within 7 pixels of each
|
||
other. This is the same algorithm as the one used by the standard
|
||
system window definition function. */
|
||
*zoomed = false;
|
||
GetWindowStandardState(theWindow,&stdState);
|
||
SetPt(&p, curState.left, curState.top);
|
||
SetRect(&r, stdState.left, stdState.top, stdState.left, stdState.top);
|
||
InsetRect(&r, -7, -7);
|
||
if (PtInRect(p, &r)) {
|
||
SetPt(&p, curState.right, curState.bottom);
|
||
SetRect(&r, stdState.right, stdState.bottom, stdState.right,
|
||
stdState.bottom);
|
||
InsetRect(&r, -7, -7);
|
||
*zoomed = PtInRect(p, &r);
|
||
};
|
||
if (*zoomed) {
|
||
GetWindowUserState(theWindow,userState);
|
||
} else {
|
||
*userState = curState;
|
||
};
|
||
SetPort_(savedPort);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_ScaleFontSize - Scale Font Size
|
||
|
||
Entry: fontNum = font number.
|
||
fontSize = nominal font size.
|
||
percent = percent change in size.
|
||
laser = true if laserwriter.
|
||
|
||
Exit: function result = scaled font size.
|
||
|
||
The nominal font size is multiplied by the percentage,
|
||
then truncated. For non-laserwriters it is then rounded down
|
||
to the nearest font size which is available in that true size,
|
||
without font manager scaling, or which can be generated by doubling
|
||
an existing font size.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
short utl_ScaleFontSize (short fontNum, short fontSize, short percent,
|
||
Boolean laser)
|
||
|
||
{
|
||
short nSize; /* new size */
|
||
short x; /* new test size */
|
||
|
||
nSize = fontSize * percent / 100;
|
||
if (!laser) {
|
||
x = nSize;
|
||
while (x > 0) {
|
||
if (RealFont(fontNum, x)) break;
|
||
if (!(x&1) && RealFont(fontNum, x>>1)) break;
|
||
x--;
|
||
};
|
||
if (x) nSize = x;
|
||
};
|
||
return nSize;
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_SpinCursor - Animate cursor.
|
||
|
||
After calling InitSpinCursor to initialize an animated cursor, call
|
||
SpinCursor periodically to make the cursor animate.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
void utl_SpinCursor (void)
|
||
|
||
{
|
||
CursHandle h; /* handle to cursor */
|
||
long ticksNow; /* current tick count */
|
||
|
||
ticksNow = TickCount();
|
||
if (ticksNow < LastTick + TickInterval) return;
|
||
LastTick = ticksNow;
|
||
CurCurs++;
|
||
if (CurCurs >= NumCurs) CurCurs = 0;
|
||
h = CursArray[CurCurs];
|
||
SetCursor(*h);
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_StaggerWindow - Stagger a New Window
|
||
|
||
Entry: windRect = window portrect.
|
||
initialOffset = intitial pixel offset of window from corner.
|
||
offset = offset for subsequent staggered windows.
|
||
|
||
Exit: pos = window position.
|
||
|
||
According to HIN 6, a new window should be positioned as follows:
|
||
"The first document window should be positioned in the upper-left corner
|
||
of the gray area of the main screen (the screen with the menu bar).
|
||
Each additional independent window should be staggered from the upper-left
|
||
corner of the screen that contains the largest portion of the
|
||
frontmost window." Also, "When a window is used or closed, its original
|
||
position becomes available again. The next window opened should use this
|
||
position. Similarly, if a window is moved onto a previously available
|
||
position, that position becomes unavailable again."
|
||
|
||
This routine implements these rules. A position is considered to be
|
||
"unavailable" if some other window is within (offset+1)/2 pixels of the
|
||
position in both the vertical and horizontal directions.
|
||
|
||
If all slots are occupied, the routine attempts to locate the first one
|
||
which is occupied by only one other window. If this attempt fails, it
|
||
tries to locate one which is occupied by only two other windows, etc.
|
||
Thus, if the screen is filled with staggered windows, subsequent windows
|
||
will be staggered on top of the existing ones, forming a second "layer."
|
||
If this layer fills up, a third layer is started, etc.
|
||
|
||
Steve Dorner, UIUC Computing Services Office 9/27/90
|
||
Invisible windows are no longer considered by the function.
|
||
Horizontal offset is 2 pixels on small screens
|
||
Steve Dorner, UIUC Computing Services Office 3/92
|
||
Leaving 2 pixel margin at screen bottom to allow for autoscroll
|
||
Added optional insets
|
||
Steve Dorner, UIUC Computing Services Office 4/92
|
||
Added parameter for specifying a particular device
|
||
_____________________________________________________________________*/
|
||
|
||
#define SIZE_9 540 /* a 9" (or so) screen */ /* sd */
|
||
#define OFF_9 3 /* horizontal offset for 9" screen */ /* sd */
|
||
void utl_StaggerWindow (WindowPtr theWindow,Rect *windRect, short initialOffset, short offset, short titleBarHeight, short leftRimWidth,
|
||
Point *pos,short specificDevice)
|
||
|
||
{
|
||
MyWindowPtr win; /* pointer to one of our own window structures */
|
||
GrafPtr savedPort; /* saved grafport */
|
||
short offsetDiv2; /* offset/2 */
|
||
short windHeight; /* window height */
|
||
short windWidth; /* window width */
|
||
WindowPtr frontWind; /* pointer to front window */
|
||
GDHandle gd; /* GDevice */
|
||
Rect screenRect; /* screen rectangle */
|
||
Rect junkRect; /* window rectangle */
|
||
Boolean hasMB; /* true if screen has menu bar */
|
||
Point initPos; /* initial staggered window position */
|
||
Point curPos; /* current staggered window position */
|
||
WindowPtr curWind; /* pointer to current window */
|
||
MyWindowPtr curWindWin; /* the MyWindow version of the current window */
|
||
Point windPos; /* current window position */
|
||
short deltaH; /* horizontal distance */
|
||
short deltaV; /* vertical distance */
|
||
short layer; /* layer number */
|
||
short nOccupied; /* number windows occupying cur pos */
|
||
Boolean noPos; /* true if no position is on screen */
|
||
Boolean is9; /* is this a 9" screen? */ /* sd */
|
||
|
||
win = GetWindowMyWindowPtr (theWindow);
|
||
GetPort(&savedPort);
|
||
offsetDiv2 = (offset+1)>>1;
|
||
windHeight = windRect->bottom - windRect->top;
|
||
windWidth = windRect->right - windRect->left;
|
||
frontWind = UglyHackFrontWindow ? UglyHackFrontWindow : FindTopUserWindow();
|
||
gd = nil;
|
||
if (specificDevice) {
|
||
utl_GetIndGD(specificDevice,&gd,&screenRect,&hasMB);
|
||
} else if (frontWind) {
|
||
utl_GetWindGD(frontWind, &gd, &screenRect, &junkRect, &hasMB);
|
||
}
|
||
if (!gd)
|
||
{
|
||
gd = GetMainDevice();
|
||
hasMB = true;
|
||
screenRect = (*gd)->gdRect;
|
||
};
|
||
|
||
if (!IsMyWindow(theWindow) || (win && win->windowType!=kDockable))
|
||
{
|
||
GetDisplayRect(gd,&screenRect); // Normal window; get normal rectangle
|
||
InsetRect(&screenRect,3,3);
|
||
}
|
||
else
|
||
if (hasMB) screenRect.top += utl_GetMBarHeight(); // docked - just avoid menu bar
|
||
SetPt(&initPos, screenRect.left + initialOffset + leftRimWidth,
|
||
screenRect.top + initialOffset + titleBarHeight);
|
||
is9 = screenRect.right-screenRect.left<=SIZE_9; /* sd */
|
||
layer = 1;
|
||
|
||
while (true) {
|
||
/* Test each layer number "layer", starting with 1 and incrementing by 1.
|
||
Break out of the loop when we find a position curPos which
|
||
is "occupied" by fewer than "layer" other windows. */
|
||
curPos = initPos;
|
||
noPos = true;
|
||
while (true) {
|
||
/* Test each possible position curPos. Break out of the loop
|
||
when we have exhaused the possible positions, or when we
|
||
have located one which has < layer "occupants". */
|
||
curWind = frontWind;
|
||
#ifndef NEWWAY
|
||
if (curPos.v + windHeight >= screenRect.bottom ||
|
||
curPos.h + windWidth >= screenRect.right) {
|
||
break;
|
||
};
|
||
#else
|
||
if (curPos.h + windWidth >= screenRect.right) break;
|
||
if (curPos.v + windHeight >= screenRect.bottom) curPos.v = initPos.v;
|
||
#endif
|
||
noPos = false;
|
||
nOccupied = 0;
|
||
while (curWind) {
|
||
Boolean hideme;
|
||
|
||
/* Scan the window list and count up how many of them "occupy"
|
||
the current location curPos. Break out of the loop when
|
||
we reach the end of the list, or when the count is >=
|
||
layer. */
|
||
curWindWin = GetWindowMyWindowPtr (curWind);
|
||
hideme = curWindWin ? curWindWin->hideme : false;
|
||
if (IsWindowVisible(curWind) && !(IsKnownWindowMyWindow(curWind) && hideme)) { /* sd */
|
||
SetPt(&windPos, 0, 0);
|
||
SetPort_(GetWindowPort(curWind));
|
||
LocalToGlobal(&windPos);
|
||
deltaH = curPos.h - windPos.h;
|
||
deltaV = curPos.v - windPos.v;
|
||
if (deltaH < 0) deltaH = -deltaH;
|
||
if (deltaV < 0) deltaV = -deltaV;
|
||
if (deltaH <= offsetDiv2 && deltaV <= offsetDiv2) {
|
||
nOccupied++;
|
||
if (nOccupied >= layer) break;
|
||
};
|
||
}; /* sd */
|
||
curWind = GetNextWindow(curWind);
|
||
};
|
||
if (!curWind) break;
|
||
if (initialOffset) curPos.h += is9 ? OFF_9 : offset; // docked windows we don't nudge to the right.
|
||
curPos.v += offset;
|
||
};
|
||
if (!curWind || noPos) break;
|
||
layer++;
|
||
};
|
||
SetPort_(savedPort);
|
||
|
||
// Make sure we're OK with docked windows
|
||
SetRect(&junkRect,curPos.h,curPos.v,curPos.h+windWidth,curPos.v+windHeight);
|
||
DockedWinReduce(theWindow,&junkRect,&screenRect);
|
||
SetPt(&initPos, screenRect.left + initialOffset + leftRimWidth,
|
||
screenRect.top + initialOffset + titleBarHeight);
|
||
if (initPos.h > curPos.h) curPos.h = initPos.h;
|
||
if (initPos.v > curPos.v) curPos.v = initPos.v;
|
||
|
||
*pos = curPos;
|
||
}
|
||
#if !(TARGET_RT_MAC_CFM)
|
||
|
||
/*______________________________________________________________________
|
||
|
||
CancelFilter - Command Period Dialog Filter Proc.
|
||
|
||
Entry: theDialog = pointer to dialog record.
|
||
theEvent = pointer to event record.
|
||
|
||
Exit: if command-period or escape typed:
|
||
|
||
function result = true.
|
||
itemHit = item number of cancel button.
|
||
|
||
else if user specified a filterProc on the call to
|
||
utl_StopAlert:
|
||
|
||
user's filterProc called, function result and itemHit
|
||
returned by user's filterProc.
|
||
|
||
else:
|
||
|
||
function result = false.
|
||
itemHit = undefined.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
static pascal Boolean CancelFilter (DialogPtr theDialog,
|
||
EventRecord *theEvent, short *itemHit)
|
||
|
||
{
|
||
short key; /* ascii code of key pressed */
|
||
|
||
if (theEvent->what != keyDown && theEvent->what != autoKey) {
|
||
if (Filter) {
|
||
return (*Filter)(theDialog, theEvent, itemHit);
|
||
} else {
|
||
return false;
|
||
};
|
||
} else {
|
||
key = theEvent->message & charCodeMask;
|
||
if (key == escapeKey) {
|
||
*itemHit = CancelItem;
|
||
utl_FlashButton(theDialog, CancelItem);
|
||
return true;
|
||
} else if ((theEvent->modifiers & cmdKey) &&
|
||
(key == '.')) {
|
||
*itemHit = CancelItem;
|
||
utl_FlashButton(theDialog, CancelItem);
|
||
return true;
|
||
} else if (Filter) {
|
||
return (*Filter)(theDialog, theEvent, itemHit);
|
||
} else if (key == returnKey || key==enterKey) {
|
||
*itemHit = 1;
|
||
utl_FlashButton(theDialog, 1);
|
||
return true;
|
||
} else {
|
||
return false;
|
||
};
|
||
};
|
||
}
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_StopAlert - Present Stop Alert
|
||
|
||
Entry: alertID = resource id of alert.
|
||
filterProc = pointer to filter proc.
|
||
cancelItem = item number of cancel button, or 0 if
|
||
none.
|
||
|
||
Exit: function result = item number
|
||
|
||
This routine is identical to the Dialog Manager routine StopAlert,
|
||
except that it centers the alert on the main window, and if requested,
|
||
command/period or the Escape key is treated the same as a click on the
|
||
Cancel button.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
short utl_StopAlert (short alertID, ModalFilterProcPtr filterProc,
|
||
short cancelItem)
|
||
|
||
{
|
||
Handle h; /* handle to alert resource */
|
||
short result; /* function result */
|
||
|
||
h = GetResource_('ALRT', alertID);
|
||
HLock(h);
|
||
utl_CenterDlogRect(*(Rect**)h, false);
|
||
if (cancelItem) {
|
||
Filter = filterProc;
|
||
CancelItem = cancelItem;
|
||
result = StopAlert(alertID, CancelFilter);
|
||
} else {
|
||
result = StopAlert(alertID, filterProc);
|
||
};
|
||
HUnlock(h);
|
||
return result;
|
||
}
|
||
#endif
|
||
|
||
/*______________________________________________________________________
|
||
|
||
utl_VolIsMFS - Test for MFS volume.
|
||
|
||
Entry: vRefNum = volume reference number.
|
||
|
||
Exit: function result = true if volume is MFS.
|
||
_____________________________________________________________________*/
|
||
|
||
|
||
Boolean utl_VolIsMFS (short vRefNum)
|
||
|
||
{
|
||
HParamBlockRec vBlock; /* vol info param block */
|
||
|
||
vBlock.volumeParam.ioNamePtr = nil;
|
||
vBlock.volumeParam.ioVolIndex = 0;
|
||
vBlock.volumeParam.ioVRefNum = vRefNum;
|
||
vBlock.volumeParam.ioVSigWord = 0xd2d7; /* in case we don't have HFS */
|
||
(void) PBHGetVInfo(&vBlock, false);
|
||
return vBlock.volumeParam.ioVSigWord == 0xd2d7;
|
||
}
|
||
|
||
/*----------------------------------------------------------------------------
|
||
GetDropLocationDirectory
|
||
|
||
Given an 'alis' drop location AEDesc, return the volume reference
|
||
number and directory ID of the directory.
|
||
|
||
Entry: dropLocation = pointer to 'alis' AEDesc record.
|
||
|
||
Exit: function result = error code.
|
||
*volumeID = volume reference number.
|
||
*directoryID = directory ID.
|
||
|
||
From Apple "HFS Drag Sample" sample code.
|
||
----------------------------------------------------------------------------*/
|
||
|
||
OSErr GetDropLocationDirectory (AEDesc *dropLocation, short *volumeID,
|
||
long *directoryID)
|
||
{
|
||
OSErr err = noErr;
|
||
AEDesc targetDescriptor;
|
||
FSSpec targetLocation;
|
||
CInfoPBRec getTargetInfo;
|
||
|
||
err = AECoerceDesc(dropLocation, typeFSS, &targetDescriptor);
|
||
if (err != noErr) return err;
|
||
|
||
AEGetDescData(&targetDescriptor, &targetLocation, sizeof(FSSpec));
|
||
|
||
err = AEDisposeDesc(&targetDescriptor);
|
||
if (err != noErr) return err;
|
||
|
||
IsAlias(&targetLocation,&targetLocation);
|
||
|
||
getTargetInfo.dirInfo.ioNamePtr = targetLocation.name;
|
||
getTargetInfo.dirInfo.ioVRefNum = targetLocation.vRefNum;
|
||
getTargetInfo.dirInfo.ioFDirIndex = 0;
|
||
getTargetInfo.dirInfo.ioDrDirID = targetLocation.parID;
|
||
|
||
err = PBGetCatInfoSync(&getTargetInfo);
|
||
if (err != noErr) return err;
|
||
|
||
*directoryID = getTargetInfo.dirInfo.ioDrDirID;
|
||
*volumeID = targetLocation.vRefNum;
|
||
return noErr;
|
||
}
|
||
|
||
|
||
|
||
/*----------------------------------------------------------------------------
|
||
DragTargetWasTrash
|
||
|
||
Check to see if the target of a drag and drop was the Finder trashcan.
|
||
|
||
Entry: dragRef = drag reference.
|
||
|
||
Exit: function result = true if target was trash.
|
||
----------------------------------------------------------------------------*/
|
||
|
||
Boolean DragTargetWasTrash (DragReference dragRef)
|
||
{
|
||
AEDesc dropLocation;
|
||
OSErr err = noErr;
|
||
long dropDirID, trashDirID;
|
||
short dropVRefNum, trashVRefNum;
|
||
|
||
err = GetDropLocation(dragRef, &dropLocation);
|
||
if (err != noErr) return false;
|
||
|
||
if (dropLocation.descriptorType == typeNull) goto exit;
|
||
|
||
err = GetDropLocationDirectory(&dropLocation, &dropVRefNum, &dropDirID);
|
||
if (err != noErr) goto exit;
|
||
|
||
err = FindFolder(dropVRefNum, kTrashFolderType, false, &trashVRefNum,
|
||
&trashDirID);
|
||
if (err != noErr) goto exit;
|
||
|
||
if (dropVRefNum != trashVRefNum || dropDirID != trashDirID) goto exit;
|
||
|
||
AEDisposeDesc(&dropLocation);
|
||
return true;
|
||
|
||
exit:
|
||
|
||
AEDisposeDesc(&dropLocation);
|
||
return false;
|
||
}
|